@orion-studios/payload-studio 0.6.0-beta.10 → 0.6.0-beta.103

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 (48) hide show
  1. package/dist/admin/client.js +2073 -610
  2. package/dist/admin/client.mjs +2048 -587
  3. package/dist/admin/index.d.mts +2 -2
  4. package/dist/admin/index.d.ts +2 -2
  5. package/dist/admin/index.js +129 -16
  6. package/dist/admin/index.mjs +1 -1
  7. package/dist/admin-app/client.js +2 -4
  8. package/dist/admin-app/client.mjs +1 -1
  9. package/dist/admin-app/index.d.mts +2 -2
  10. package/dist/admin-app/index.d.ts +2 -2
  11. package/dist/admin-app/styles.css +316 -3
  12. package/dist/admin.css +98 -2
  13. package/dist/builder-v2/client.d.mts +18 -0
  14. package/dist/builder-v2/client.d.ts +18 -0
  15. package/dist/builder-v2/client.js +3298 -0
  16. package/dist/builder-v2/client.mjs +3173 -0
  17. package/dist/builder-v2/index.d.mts +242 -0
  18. package/dist/builder-v2/index.d.ts +242 -0
  19. package/dist/builder-v2/index.js +805 -0
  20. package/dist/builder-v2/index.mjs +755 -0
  21. package/dist/builder-v2/styles.css +2365 -0
  22. package/dist/{chunk-KPIX7OSV.mjs → chunk-3ZKXHSG5.mjs} +2 -4
  23. package/dist/{chunk-PF3EBZXF.mjs → chunk-7ZMXZRBP.mjs} +39 -3
  24. package/dist/{chunk-WLOPFFN2.mjs → chunk-JC3UV74N.mjs} +129 -16
  25. package/dist/{chunk-XKUTZ7IU.mjs → chunk-NGLIA2OE.mjs} +53 -2
  26. package/dist/{chunk-OTHERBGX.mjs → chunk-ZADL33R6.mjs} +1 -1
  27. package/dist/{index-CkT_eyhK.d.ts → index-BV0vEGl6.d.ts} +3 -2
  28. package/dist/{index-Cv-6qnrw.d.mts → index-D5zrOdyv.d.mts} +3 -1
  29. package/dist/{index-52HdVLQq.d.ts → index-DAdN56fM.d.ts} +1 -1
  30. package/dist/{index-Bm2SaC3r.d.mts → index-DLfPOqYA.d.mts} +3 -2
  31. package/dist/{index-Crx_MtPw.d.ts → index-Dv-Alx4h.d.ts} +3 -1
  32. package/dist/{index-DEQC3Dwj.d.mts → index-G_uTNffQ.d.mts} +1 -1
  33. package/dist/index.d.mts +4 -4
  34. package/dist/index.d.ts +4 -4
  35. package/dist/index.js +220 -20
  36. package/dist/index.mjs +4 -4
  37. package/dist/nextjs/index.js +39 -3
  38. package/dist/nextjs/index.mjs +2 -2
  39. package/dist/{sitePreviewTypes-BkHCWxNW.d.mts → sitePreviewTypes-BrJwGzJj.d.mts} +1 -1
  40. package/dist/{sitePreviewTypes-BkHCWxNW.d.ts → sitePreviewTypes-BrJwGzJj.d.ts} +1 -1
  41. package/dist/studio-pages/builder.css +66 -5
  42. package/dist/studio-pages/client.js +618 -73
  43. package/dist/studio-pages/client.mjs +641 -96
  44. package/dist/studio-pages/index.d.mts +1 -1
  45. package/dist/studio-pages/index.d.ts +1 -1
  46. package/dist/studio-pages/index.js +91 -4
  47. package/dist/studio-pages/index.mjs +2 -2
  48. package/package.json +23 -3
@@ -749,7 +749,7 @@ var init_OrionBlocksFieldImpl = __esm({
749
749
  const schemaPath = schemaPathFromProps ?? name;
750
750
  const minRows = minRowsProp ?? (required ? 1 : 0);
751
751
  const { setDocFieldPreferences } = (0, import_DocumentInfo.useDocumentInfo)();
752
- const { addFieldRow, dispatchFields, getFields, moveFieldRow, removeFieldRow, replaceState, setModified } = (0, import_Form.useForm)();
752
+ const { addFieldRow, dispatchFields, getFields: getFields2, moveFieldRow, removeFieldRow, replaceState, setModified } = (0, import_Form.useForm)();
753
753
  const { code: locale } = (0, import_Locale.useLocale)();
754
754
  const configContext = (0, import_Config.useConfig)();
755
755
  const config = configContext?.config ?? {};
@@ -911,7 +911,7 @@ var init_OrionBlocksFieldImpl = __esm({
911
911
  (rowIndex) => {
912
912
  const result = clipboardCopy({
913
913
  getDataToCopy: () => reduceFormStateByPath({
914
- formState: getFields(),
914
+ formState: getFields2(),
915
915
  path: safePath,
916
916
  rowIndex
917
917
  }),
@@ -929,13 +929,13 @@ var init_OrionBlocksFieldImpl = __esm({
929
929
  import_sonner.toast.success(t("general:copied"));
930
930
  }
931
931
  },
932
- [clientBlocks, getFields, safePath, t, type]
932
+ [clientBlocks, getFields2, safePath, t, type]
933
933
  );
934
934
  const pasteRow = (0, import_react10.useCallback)(
935
935
  (rowIndex) => {
936
936
  const result = clipboardPaste({
937
937
  onPaste: (dataFromClipboard) => {
938
- const formState = getFields();
938
+ const formState = getFields2();
939
939
  const newState = mergeFormStateFromClipboard({
940
940
  dataFromClipboard,
941
941
  formState,
@@ -952,11 +952,11 @@ var init_OrionBlocksFieldImpl = __esm({
952
952
  import_sonner.toast.error(result);
953
953
  }
954
954
  },
955
- [clientBlocks, getFields, replaceState, safePath, setModified, t]
955
+ [clientBlocks, getFields2, replaceState, safePath, setModified, t]
956
956
  );
957
957
  const pasteBlocks = (0, import_react10.useCallback)(
958
958
  (dataFromClipboard) => {
959
- const formState = getFields();
959
+ const formState = getFields2();
960
960
  const newState = mergeFormStateFromClipboard({
961
961
  dataFromClipboard,
962
962
  formState,
@@ -965,7 +965,7 @@ var init_OrionBlocksFieldImpl = __esm({
965
965
  replaceState(newState);
966
966
  setModified(true);
967
967
  },
968
- [getFields, replaceState, safePath, setModified]
968
+ [getFields2, replaceState, safePath, setModified]
969
969
  );
970
970
  const hasMaxRows = Boolean(maxRows && rows.length >= maxRows);
971
971
  const fieldErrorCount = errorPaths.length;
@@ -1042,7 +1042,7 @@ var init_OrionBlocksFieldImpl = __esm({
1042
1042
  className: `${baseClass}__header-action`,
1043
1043
  disabled,
1044
1044
  getDataToCopy: () => reduceFormStateByPath({
1045
- formState: getFields(),
1045
+ formState: getFields2(),
1046
1046
  path: safePath
1047
1047
  }),
1048
1048
  onPaste: pasteBlocks,
@@ -1171,6 +1171,9 @@ __export(client_exports, {
1171
1171
  AdminStudioContactFormView: () => AdminStudioContactFormView,
1172
1172
  AdminStudioDashboard: () => AdminStudioDashboard,
1173
1173
  AdminStudioFooterGlobalView: () => AdminStudioFooterGlobalView,
1174
+ AdminStudioFormDetailView: () => AdminStudioFormDetailView,
1175
+ AdminStudioFormSubmissionView: () => AdminStudioFormSubmissionView,
1176
+ AdminStudioFormUploadView: () => AdminStudioFormUploadView,
1174
1177
  AdminStudioFormsView: () => AdminStudioFormsView,
1175
1178
  AdminStudioGlobalsView: () => AdminStudioGlobalsView,
1176
1179
  AdminStudioHeaderGlobalView: () => AdminStudioHeaderGlobalView,
@@ -1196,6 +1199,7 @@ __export(client_exports, {
1196
1199
  StatusBadge: () => StatusBadge,
1197
1200
  StudioBackBreadcrumb: () => StudioBackBreadcrumb,
1198
1201
  StudioContactFormRedirect: () => StudioContactFormRedirect,
1202
+ StudioDocumentRedirect: () => StudioDocumentRedirect,
1199
1203
  StudioSectionLayout: () => StudioSectionLayout,
1200
1204
  ThemeProvider: () => ThemeProvider,
1201
1205
  ThemeSwitcher: () => ThemeSwitcher,
@@ -1231,17 +1235,22 @@ var resolveUploadUrl = (value) => {
1231
1235
  var resolveLogoUrl = (settings) => {
1232
1236
  return resolveUploadUrl(settings.logo) || resolveUploadUrl(settings.adminLogo) || resolveUploadUrl(settings.brandLogo) || null;
1233
1237
  };
1238
+ var resolveLogoOnDarkUrl = (settings) => {
1239
+ return resolveUploadUrl(settings.logoOnDark) || resolveUploadUrl(settings.logoDark) || resolveUploadUrl(settings.adminLogoDark) || resolveUploadUrl(settings.adminLogoOnDark) || resolveUploadUrl(settings.brandLogoDark) || null;
1240
+ };
1234
1241
  var cachedBranding = null;
1235
- function useSiteBranding(defaultName, defaultLogoUrl) {
1242
+ function useSiteBranding(defaultName, defaultLogoUrl, defaultLogoOnDarkUrl) {
1236
1243
  const [branding, setBranding] = (0, import_react.useState)(() => {
1237
1244
  if (cachedBranding) {
1238
1245
  return {
1239
1246
  logoUrl: cachedBranding.logoUrl || defaultLogoUrl || null,
1247
+ logoOnDarkUrl: cachedBranding.logoOnDarkUrl || defaultLogoOnDarkUrl || null,
1240
1248
  siteName: cachedBranding.siteName || defaultName || null
1241
1249
  };
1242
1250
  }
1243
1251
  return {
1244
1252
  logoUrl: defaultLogoUrl || null,
1253
+ logoOnDarkUrl: defaultLogoOnDarkUrl || null,
1245
1254
  siteName: defaultName || null
1246
1255
  };
1247
1256
  });
@@ -1258,9 +1267,11 @@ function useSiteBranding(defaultName, defaultLogoUrl) {
1258
1267
  if (!record) return;
1259
1268
  const siteName = pickString(record.siteName);
1260
1269
  const logoUrl = resolveLogoUrl(record);
1261
- cachedBranding = { logoUrl, siteName };
1270
+ const logoOnDarkUrl = resolveLogoOnDarkUrl(record);
1271
+ cachedBranding = { logoOnDarkUrl, logoUrl, siteName };
1262
1272
  if (!cancelled) {
1263
1273
  setBranding({
1274
+ logoOnDarkUrl: logoOnDarkUrl || defaultLogoOnDarkUrl || null,
1264
1275
  logoUrl: logoUrl || defaultLogoUrl || null,
1265
1276
  siteName: siteName || defaultName || null
1266
1277
  });
@@ -1272,16 +1283,20 @@ function useSiteBranding(defaultName, defaultLogoUrl) {
1272
1283
  return () => {
1273
1284
  cancelled = true;
1274
1285
  };
1275
- }, [defaultLogoUrl, defaultName]);
1286
+ }, [defaultLogoOnDarkUrl, defaultLogoUrl, defaultName]);
1276
1287
  return branding;
1277
1288
  }
1278
1289
 
1279
1290
  // src/admin/components/Logo.tsx
1280
1291
  var import_jsx_runtime = require("react/jsx-runtime");
1281
- function Logo({ brandName = "Orion Studio", logoUrl } = {}) {
1282
- const branding = useSiteBranding(brandName, logoUrl);
1292
+ function Logo({ brandName = "Orion Studio", logoOnDarkUrl, logoUrl } = {}) {
1293
+ const branding = useSiteBranding(brandName, logoUrl, logoOnDarkUrl);
1283
1294
  const resolvedName = branding.siteName || brandName;
1284
1295
  const resolvedLogo = branding.logoUrl || logoUrl || null;
1296
+ const resolvedLogoOnDark = branding.logoOnDarkUrl || logoOnDarkUrl || resolvedLogo || "";
1297
+ const hasDarkLogoVariant = Boolean(
1298
+ resolvedLogo && resolvedLogoOnDark.trim().length > 0 && resolvedLogoOnDark !== resolvedLogo
1299
+ );
1285
1300
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1286
1301
  "div",
1287
1302
  {
@@ -1300,8 +1315,6 @@ function Logo({ brandName = "Orion Studio", logoUrl } = {}) {
1300
1315
  className: "orion-admin-logo-mark",
1301
1316
  style: {
1302
1317
  alignItems: "center",
1303
- background: "var(--orion-cms-logo-bg, var(--admin-accent, #3b82f6))",
1304
- borderRadius: "var(--orion-cms-logo-radius, var(--admin-radius-md, 8px))",
1305
1318
  display: "flex",
1306
1319
  flexShrink: 0,
1307
1320
  height: 32,
@@ -1309,14 +1322,25 @@ function Logo({ brandName = "Orion Studio", logoUrl } = {}) {
1309
1322
  overflow: "hidden",
1310
1323
  width: 32
1311
1324
  },
1312
- children: resolvedLogo ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1313
- "img",
1314
- {
1315
- alt: `${resolvedName} logo`,
1316
- src: resolvedLogo,
1317
- style: { height: "100%", objectFit: "cover", width: "100%" }
1318
- }
1319
- ) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1325
+ children: resolvedLogo ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1326
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1327
+ "img",
1328
+ {
1329
+ alt: `${resolvedName} logo`,
1330
+ className: `orion-admin-logo-image orion-admin-logo-image--default${hasDarkLogoVariant ? "" : " is-only-logo"}`,
1331
+ src: resolvedLogo
1332
+ }
1333
+ ),
1334
+ hasDarkLogoVariant ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1335
+ "img",
1336
+ {
1337
+ alt: "",
1338
+ "aria-hidden": "true",
1339
+ className: "orion-admin-logo-image orion-admin-logo-image--dark",
1340
+ src: resolvedLogoOnDark
1341
+ }
1342
+ ) : null
1343
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1320
1344
  "svg",
1321
1345
  {
1322
1346
  fill: "none",
@@ -2554,7 +2578,7 @@ var navItemIsActive = (pathname, item) => {
2554
2578
  };
2555
2579
 
2556
2580
  // src/shared/studioSections.ts
2557
- var studioRoles = /* @__PURE__ */ new Set(["admin", "editor", "client"]);
2581
+ var studioRoles = /* @__PURE__ */ new Set(["admin", "developer", "editor", "client"]);
2558
2582
  var studioIcons = new Set(adminNavIcons);
2559
2583
  var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
2560
2584
  var isAbsoluteExternalURL2 = (value) => /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(value) || value.startsWith("//");
@@ -2752,7 +2776,7 @@ var buildStudioNavItems = (props, adminBasePath) => {
2752
2776
  icon: "tools",
2753
2777
  label: "Admin Tools",
2754
2778
  matchPrefixes: [toolsPath, resolveAdminPath(adminBasePath, "/collections/users")],
2755
- roles: ["admin"]
2779
+ roles: ["admin", "developer"]
2756
2780
  };
2757
2781
  const extensionItems = sections.map((section) => ({
2758
2782
  href: resolveAdminPath(adminBasePath, section.href),
@@ -3035,14 +3059,12 @@ function AdminShellClient({
3035
3059
  onLogout,
3036
3060
  storageKey = "orion-admin-shell-collapsed"
3037
3061
  }) {
3038
- const [collapsed, setCollapsed] = (0, import_react14.useState)(false);
3062
+ const [collapsed, setCollapsed] = (0, import_react14.useState)(true);
3039
3063
  const [loggingOut, setLoggingOut] = (0, import_react14.useState)(false);
3040
3064
  (0, import_react14.useEffect)(() => {
3041
3065
  try {
3042
3066
  const stored = window.localStorage.getItem(storageKey);
3043
- if (stored === "1") {
3044
- setCollapsed(true);
3045
- }
3067
+ setCollapsed(stored === "1");
3046
3068
  } catch {
3047
3069
  }
3048
3070
  }, [storageKey]);
@@ -3193,9 +3215,9 @@ var import_react16 = require("react");
3193
3215
  var import_link = __toESM(require("next/link"));
3194
3216
  var import_jsx_runtime21 = require("react/jsx-runtime");
3195
3217
  var SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1e3;
3196
- var isRole = (value) => value === "admin" || value === "editor" || value === "client";
3197
- var canReviewForms = (role) => role === "admin" || role === "editor";
3198
- var canCreatePages = (role) => role === "admin" || role === "editor";
3218
+ var isRole = (value) => value === "admin" || value === "client" || value === "developer" || value === "editor";
3219
+ var canReviewForms = (role) => role === "admin" || role === "developer" || role === "editor";
3220
+ var canCreatePages = (role) => role === "admin" || role === "developer" || role === "editor";
3199
3221
  var canAccess = (role, roles) => {
3200
3222
  if (!roles || roles.length === 0) {
3201
3223
  return true;
@@ -3671,7 +3693,7 @@ function AdminStudioDashboardClient({
3671
3693
  label: "Manage Media",
3672
3694
  tone: "ghost"
3673
3695
  });
3674
- if (role === "admin") {
3696
+ if (role === "admin" || role === "developer") {
3675
3697
  actions.push({
3676
3698
  description: "Manage users, roles, and fallback tools.",
3677
3699
  href: toolsPath,
@@ -3950,7 +3972,7 @@ var buildSectionLinks = (adminBasePath, sections, formsEnabled, globalsBasePath)
3950
3972
  href: resolveAdminPath2(adminBasePath, "/tools"),
3951
3973
  id: "admin-tools",
3952
3974
  label: "Admin Tools",
3953
- roles: ["admin"]
3975
+ roles: ["admin", "developer"]
3954
3976
  }
3955
3977
  ];
3956
3978
  const seen = /* @__PURE__ */ new Set();
@@ -4016,15 +4038,16 @@ function AdminStudioDashboard(rawProps) {
4016
4038
  }
4017
4039
 
4018
4040
  // src/admin/components/studio/AdminStudioPagesListView.tsx
4019
- var import_react17 = require("react");
4041
+ var import_react19 = require("react");
4020
4042
  var import_link2 = __toESM(require("next/link"));
4043
+ var import_navigation3 = require("next/navigation");
4044
+ var import_ui7 = require("@payloadcms/ui");
4045
+
4046
+ // src/admin/components/studio/AdminStudioNewPageView.tsx
4047
+ var import_react17 = require("react");
4021
4048
  var import_ui5 = require("@payloadcms/ui");
4022
4049
  var import_jsx_runtime23 = require("react/jsx-runtime");
4023
- var isAdmin = (user) => {
4024
- if (!user || typeof user !== "object") return false;
4025
- const role = user.role;
4026
- return typeof role === "string" && role === "admin";
4027
- };
4050
+ var pageTemplates = ["standard", "landing", "services", "contact"];
4028
4051
  var getPropString3 = (props, key, fallback) => {
4029
4052
  if (!props || typeof props !== "object") return fallback;
4030
4053
  const direct = props[key];
@@ -4036,83 +4059,107 @@ var getPropString3 = (props, key, fallback) => {
4036
4059
  }
4037
4060
  return fallback;
4038
4061
  };
4039
- function AdminStudioPagesListView(props) {
4062
+ var canManagePages = (user) => {
4063
+ if (!user || typeof user !== "object") return false;
4064
+ const role = user.role;
4065
+ return role === "admin" || role === "developer" || role === "editor";
4066
+ };
4067
+ var slugify = (value) => value.toLowerCase().trim().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-");
4068
+ function AdminStudioNewPageView(props) {
4040
4069
  const { user } = (0, import_ui5.useAuth)();
4041
- const pagesCollectionSlug = getPropString3(props, "pagesCollectionSlug", "pages");
4042
4070
  const adminBasePath = useAdminBasePath();
4043
- const newPagePath = resolveAdminPath(adminBasePath, "/pages/new");
4044
- const [loading, setLoading] = (0, import_react17.useState)(true);
4071
+ const pagesCollectionSlug = getPropString3(props, "pagesCollectionSlug", "pages");
4072
+ const [submitting, setSubmitting] = (0, import_react17.useState)(false);
4045
4073
  const [error, setError] = (0, import_react17.useState)(null);
4046
- const [docs, setDocs] = (0, import_react17.useState)([]);
4047
- const apiURL = (0, import_react17.useMemo)(() => {
4048
- const params = new URLSearchParams({
4049
- depth: "0",
4050
- limit: "100",
4051
- sort: "-updatedAt",
4052
- draft: "true"
4053
- });
4054
- return `/api/${pagesCollectionSlug}?${params.toString()}`;
4055
- }, [pagesCollectionSlug]);
4056
- (0, import_react17.useEffect)(() => {
4057
- let cancelled = false;
4058
- const run = async () => {
4059
- setLoading(true);
4060
- setError(null);
4061
- try {
4062
- const res = await fetch(apiURL, { credentials: "include" });
4063
- if (!res.ok) {
4064
- const body = await res.text();
4065
- throw new Error(body || "Failed to fetch pages");
4066
- }
4067
- const data = await res.json();
4068
- if (!cancelled) {
4069
- setDocs(Array.isArray(data.docs) ? data.docs : []);
4070
- }
4071
- } catch (err) {
4072
- if (!cancelled) {
4073
- setError(err instanceof Error ? err.message : "Failed to fetch pages");
4074
- }
4075
- } finally {
4076
- if (!cancelled) {
4077
- setLoading(false);
4078
- }
4074
+ if (!canManagePages(user)) {
4075
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4076
+ AdminPage,
4077
+ {
4078
+ breadcrumbs: [
4079
+ { label: "Dashboard", href: adminBasePath },
4080
+ { label: "Pages", href: resolveAdminPath(adminBasePath, "/pages") },
4081
+ { label: "New Page" }
4082
+ ],
4083
+ description: "You do not have access to create pages.",
4084
+ title: "New Page",
4085
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "orion-admin-card", children: [
4086
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("strong", { children: "Access denied" }),
4087
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: "This section is restricted to administrator, developer, and editor accounts." })
4088
+ ] })
4079
4089
  }
4080
- };
4081
- void run();
4082
- return () => {
4083
- cancelled = true;
4084
- };
4085
- }, [apiURL]);
4086
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
4090
+ ) });
4091
+ }
4092
+ const createPage = async (event) => {
4093
+ event.preventDefault();
4094
+ setSubmitting(true);
4095
+ setError(null);
4096
+ try {
4097
+ const formData = new FormData(event.currentTarget);
4098
+ const titleValue = String(formData.get("title") || "").trim();
4099
+ const slugValue = String(formData.get("slug") || "").trim();
4100
+ const templateValue = String(formData.get("template") || "standard").trim();
4101
+ const template = pageTemplates.includes(templateValue) ? templateValue : "standard";
4102
+ const title = titleValue || "Untitled Page";
4103
+ const slug = slugValue || slugify(title) || "untitled-page";
4104
+ const response = await fetch(`/api/${pagesCollectionSlug}`, {
4105
+ body: JSON.stringify({
4106
+ _status: "draft",
4107
+ slug,
4108
+ template,
4109
+ title
4110
+ }),
4111
+ credentials: "include",
4112
+ headers: {
4113
+ "Content-Type": "application/json"
4114
+ },
4115
+ method: "POST"
4116
+ });
4117
+ if (!response.ok) {
4118
+ throw new Error(`Failed to create page (${response.status}).`);
4119
+ }
4120
+ const payload = await response.json();
4121
+ const id = typeof payload.id === "string" || typeof payload.id === "number" ? String(payload.id) : "";
4122
+ if (!id) {
4123
+ throw new Error("Page created but no document ID was returned.");
4124
+ }
4125
+ window.location.assign(resolveAdminPath(adminBasePath, `/pages/${id}`));
4126
+ } catch (createError) {
4127
+ setError(createError instanceof Error ? createError.message : "Failed to create page.");
4128
+ } finally {
4129
+ setSubmitting(false);
4130
+ }
4131
+ };
4132
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4087
4133
  AdminPage,
4088
4134
  {
4089
- actions: isAdmin(user) ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_link2.default, { className: "orion-admin-action-button", href: newPagePath, children: "New Page" }) : null,
4090
4135
  breadcrumbs: [
4091
4136
  { label: "Dashboard", href: adminBasePath },
4092
- { label: "Pages" }
4137
+ { label: "Pages", href: resolveAdminPath(adminBasePath, "/pages") },
4138
+ { label: "New Page" }
4093
4139
  ],
4094
- description: "Open a page to edit it in the inline custom builder.",
4095
- title: "Pages",
4096
- children: [
4097
- loading ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "orion-admin-list-meta", children: "Loading..." }) : null,
4140
+ description: "Create a new page and open it in the custom editor.",
4141
+ title: "New Page",
4142
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("form", { className: "orion-admin-form", onSubmit: createPage, children: [
4098
4143
  error ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "orion-admin-error", children: error }) : null,
4099
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "orion-admin-list", children: [
4100
- !loading && !error && docs.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "orion-admin-card", children: [
4101
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("strong", { children: "No pages yet" }),
4102
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: "Create the first page to start building content." })
4103
- ] }) : null,
4104
- docs.map((doc) => {
4105
- const id = typeof doc.id === "string" || typeof doc.id === "number" ? String(doc.id) : "";
4106
- if (!id) return null;
4107
- const title = typeof doc.title === "string" ? doc.title : "Untitled Page";
4108
- const status = typeof doc._status === "string" ? doc._status : "draft";
4109
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_link2.default, { className: "orion-admin-list-item", href: resolveAdminPath(adminBasePath, `/pages/${id}`), children: [
4110
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("strong", { children: title }) }),
4111
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "orion-admin-pill", children: status })
4112
- ] }, id);
4113
- })
4114
- ] })
4115
- ]
4144
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { children: [
4145
+ "Title",
4146
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("input", { name: "title", placeholder: "Services", required: true, type: "text" })
4147
+ ] }),
4148
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { children: [
4149
+ "Slug",
4150
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("input", { name: "slug", placeholder: "services", type: "text" })
4151
+ ] }),
4152
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { children: [
4153
+ "Template",
4154
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("select", { defaultValue: "standard", name: "template", children: [
4155
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: "standard", children: "Standard" }),
4156
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: "landing", children: "Landing" }),
4157
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: "contact", children: "Contact" }),
4158
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: "services", children: "Services" })
4159
+ ] })
4160
+ ] }),
4161
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { disabled: submitting, type: "submit", children: submitting ? "Creating..." : "Create Page" })
4162
+ ] })
4116
4163
  }
4117
4164
  ) });
4118
4165
  }
@@ -4121,16 +4168,6 @@ function AdminStudioPagesListView(props) {
4121
4168
  var import_react18 = require("react");
4122
4169
  var import_ui6 = require("@payloadcms/ui");
4123
4170
  var import_jsx_runtime24 = require("react/jsx-runtime");
4124
- var isAdmin2 = (user) => {
4125
- if (!user || typeof user !== "object") return false;
4126
- const role = user.role;
4127
- return typeof role === "string" && role === "admin";
4128
- };
4129
- var isEditor = (user) => {
4130
- if (!user || typeof user !== "object") return false;
4131
- const role = user.role;
4132
- return typeof role === "string" && role === "editor";
4133
- };
4134
4171
  var getPropString4 = (props, key, fallback) => {
4135
4172
  if (!props || typeof props !== "object") return fallback;
4136
4173
  const direct = props[key];
@@ -4158,14 +4195,8 @@ var getPageIDFromPathname = (pathname) => {
4158
4195
  return pagePart ? decodeURIComponent(pagePart) : null;
4159
4196
  };
4160
4197
  function AdminStudioPageEditView(props) {
4161
- const { user } = (0, import_ui6.useAuth)();
4162
4198
  const adminBasePath = useAdminBasePath();
4163
4199
  const iframeRef = (0, import_react18.useRef)(null);
4164
- const [saving, setSaving] = (0, import_react18.useState)(null);
4165
- const [dirty, setDirty] = (0, import_react18.useState)(false);
4166
- const [hasUnpublishedChanges, setHasUnpublishedChanges] = (0, import_react18.useState)(false);
4167
- const [canUndo, setCanUndo] = (0, import_react18.useState)(false);
4168
- const [canRedo, setCanRedo] = (0, import_react18.useState)(false);
4169
4200
  const builderBasePath = getPropString4(props, "builderBasePath", "/builder");
4170
4201
  const pagesPath = resolveAdminPath(adminBasePath, "/pages");
4171
4202
  const pageIDFromParams = (0, import_react18.useMemo)(() => getParam(props.params, "id"), [props.params]);
@@ -4182,96 +4213,6 @@ function AdminStudioPageEditView(props) {
4182
4213
  }
4183
4214
  setDidResolvePathFallback(true);
4184
4215
  }, [pageIDFromParams]);
4185
- const canPublish = isAdmin2(user) || isEditor(user);
4186
- const refreshUnpublishedState = async (id) => {
4187
- try {
4188
- const response = await fetch(
4189
- `/api/pages/versions?depth=0&limit=25&sort=-updatedAt&where[parent][equals]=${encodeURIComponent(id)}`,
4190
- {
4191
- credentials: "include"
4192
- }
4193
- );
4194
- if (!response.ok) {
4195
- return;
4196
- }
4197
- const payload = await response.json();
4198
- const docs = Array.isArray(payload.docs) ? payload.docs : [];
4199
- let latestDraft = 0;
4200
- let latestPublished = 0;
4201
- docs.forEach((doc) => {
4202
- const status = doc.version?._status;
4203
- const millis = typeof doc.updatedAt === "string" ? Date.parse(doc.updatedAt) : Number.NaN;
4204
- if (!Number.isFinite(millis)) {
4205
- return;
4206
- }
4207
- if (status === "draft") {
4208
- latestDraft = Math.max(latestDraft, millis);
4209
- }
4210
- if (status === "published") {
4211
- latestPublished = Math.max(latestPublished, millis);
4212
- }
4213
- });
4214
- setHasUnpublishedChanges(latestDraft > 0 && latestDraft >= latestPublished);
4215
- } catch {
4216
- }
4217
- };
4218
- (0, import_react18.useEffect)(() => {
4219
- if (!pageID) {
4220
- return;
4221
- }
4222
- void refreshUnpublishedState(pageID);
4223
- }, [pageID]);
4224
- const requestSave = (status) => {
4225
- const iframe = iframeRef.current;
4226
- if (!iframe?.contentWindow) {
4227
- import_ui6.toast.error("Editor is not ready yet. Please try again.");
4228
- return;
4229
- }
4230
- setSaving(status);
4231
- iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type: "save", status }, "*");
4232
- };
4233
- const requestHistoryAction = (type) => {
4234
- const iframe = iframeRef.current;
4235
- if (!iframe?.contentWindow) {
4236
- import_ui6.toast.error("Editor is not ready yet. Please try again.");
4237
- return;
4238
- }
4239
- iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type }, "*");
4240
- };
4241
- (0, import_react18.useEffect)(() => {
4242
- const onMessage = (event) => {
4243
- const data = event.data;
4244
- if (!data || data.source !== "payload-visual-builder-child" || typeof data.type !== "string") {
4245
- return;
4246
- }
4247
- if (data.type === "dirty-state") {
4248
- setDirty(Boolean(data.dirty));
4249
- return;
4250
- }
4251
- if (data.type === "history-state") {
4252
- setCanUndo(Boolean(data.canUndo));
4253
- setCanRedo(Boolean(data.canRedo));
4254
- return;
4255
- }
4256
- if (data.type === "save-result") {
4257
- setSaving(null);
4258
- if (data.ok) {
4259
- if (data.status === "draft") {
4260
- setHasUnpublishedChanges(true);
4261
- } else if (data.status === "published") {
4262
- setHasUnpublishedChanges(false);
4263
- } else if (pageID) {
4264
- void refreshUnpublishedState(pageID);
4265
- }
4266
- import_ui6.toast.success(typeof data.message === "string" ? data.message : "Saved.");
4267
- } else {
4268
- import_ui6.toast.error(typeof data.message === "string" ? data.message : "Save failed.");
4269
- }
4270
- }
4271
- };
4272
- window.addEventListener("message", onMessage);
4273
- return () => window.removeEventListener("message", onMessage);
4274
- }, []);
4275
4216
  if (!pageID && !didResolvePathFallback) {
4276
4217
  return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
4277
4218
  /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
@@ -4312,155 +4253,25 @@ function AdminStudioPageEditView(props) {
4312
4253
  ]
4313
4254
  }
4314
4255
  ),
4315
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { display: "grid", gridTemplateRows: "auto 1fr", height: "calc(100vh - 120px)" }, children: [
4316
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
4317
- "div",
4318
- {
4319
- style: {
4320
- alignItems: "center",
4321
- background: "var(--theme-elevation-0)",
4322
- borderBottom: "1px solid var(--theme-elevation-150)",
4323
- display: "flex",
4324
- gap: "0.6rem",
4325
- justifyContent: "space-between",
4326
- padding: "0.65rem 0.9rem",
4327
- position: "sticky",
4328
- top: 0,
4329
- zIndex: 20
4330
- },
4331
- children: [
4332
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { minWidth: 0 }, children: [
4333
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { fontWeight: 900 }, children: "Page Editor" }),
4334
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
4335
- "div",
4336
- {
4337
- style: {
4338
- color: "var(--theme-elevation-600)",
4339
- fontSize: "0.85rem",
4340
- overflow: "hidden",
4341
- textOverflow: "ellipsis"
4342
- },
4343
- children: [
4344
- "Editing: ",
4345
- pageID
4346
- ]
4347
- }
4348
- )
4349
- ] }),
4350
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { alignItems: "center", display: "flex", gap: "0.5rem" }, children: [
4351
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { color: dirty ? "var(--theme-elevation-900)" : "var(--theme-elevation-600)", fontSize: "0.85rem", fontWeight: 700 }, children: dirty ? "Unsaved changes" : "All changes saved" }),
4352
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4353
- "div",
4354
- {
4355
- style: {
4356
- background: hasUnpublishedChanges ? "#fff3cd" : "var(--theme-success-50)",
4357
- border: `1px solid ${hasUnpublishedChanges ? "#f0c36d" : "var(--theme-success-300)"}`,
4358
- borderRadius: 999,
4359
- color: hasUnpublishedChanges ? "#6a4a00" : "var(--theme-success-700)",
4360
- fontSize: "0.75rem",
4361
- fontWeight: 800,
4362
- padding: "0.2rem 0.55rem",
4363
- whiteSpace: "nowrap"
4364
- },
4365
- title: hasUnpublishedChanges ? "There are saved draft changes not yet published." : "The live page matches the latest published content.",
4366
- children: hasUnpublishedChanges ? "Unpublished draft changes" : "Live is up to date"
4367
- }
4368
- ),
4369
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4370
- "button",
4371
- {
4372
- disabled: !canUndo,
4373
- onClick: () => requestHistoryAction("undo"),
4374
- style: {
4375
- border: "1px solid var(--theme-elevation-300)",
4376
- borderRadius: 12,
4377
- cursor: canUndo ? "pointer" : "not-allowed",
4378
- fontWeight: 800,
4379
- padding: "0.5rem 0.65rem"
4380
- },
4381
- type: "button",
4382
- children: "Undo"
4383
- }
4384
- ),
4385
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4386
- "button",
4387
- {
4388
- disabled: !canRedo,
4389
- onClick: () => requestHistoryAction("redo"),
4390
- style: {
4391
- border: "1px solid var(--theme-elevation-300)",
4392
- borderRadius: 12,
4393
- cursor: canRedo ? "pointer" : "not-allowed",
4394
- fontWeight: 800,
4395
- padding: "0.5rem 0.65rem"
4396
- },
4397
- type: "button",
4398
- children: "Redo"
4399
- }
4400
- ),
4401
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4402
- "button",
4403
- {
4404
- disabled: saving !== null,
4405
- onClick: () => requestSave("draft"),
4406
- style: {
4407
- border: "1px solid var(--theme-elevation-300)",
4408
- borderRadius: 12,
4409
- cursor: saving ? "not-allowed" : "pointer",
4410
- fontWeight: 800,
4411
- padding: "0.5rem 0.75rem"
4412
- },
4413
- type: "button",
4414
- children: saving === "draft" ? "Saving\u2026" : "Save Draft"
4415
- }
4416
- ),
4417
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4418
- "button",
4419
- {
4420
- disabled: !canPublish || saving !== null,
4421
- onClick: () => requestSave("published"),
4422
- style: {
4423
- background: canPublish ? "var(--theme-success-700)" : "var(--theme-elevation-300)",
4424
- border: "none",
4425
- borderRadius: 12,
4426
- color: canPublish ? "var(--theme-elevation-0)" : "var(--theme-elevation-700)",
4427
- cursor: !canPublish || saving ? "not-allowed" : "pointer",
4428
- fontWeight: 900,
4429
- padding: "0.5rem 0.75rem"
4430
- },
4431
- type: "button",
4432
- title: !canPublish ? "You do not have publish permissions." : void 0,
4433
- children: saving === "published" ? "Publishing\u2026" : "Publish"
4434
- }
4435
- )
4436
- ] })
4437
- ]
4438
- }
4439
- ),
4440
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4441
- "iframe",
4442
- {
4443
- ref: iframeRef,
4444
- src: `${builderBasePath.replace(/\/$/, "")}/${pageID}`,
4445
- style: { border: "none", height: "100%", width: "100%" },
4446
- title: "Page Builder",
4447
- onLoad: () => {
4448
- const iframe = iframeRef.current;
4449
- if (!iframe?.contentWindow) return;
4450
- iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type: "dirty-check-request" }, "*");
4451
- iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type: "history-check-request" }, "*");
4452
- }
4453
- }
4454
- )
4455
- ] })
4256
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { height: "calc(100vh - 80px)" }, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4257
+ "iframe",
4258
+ {
4259
+ ref: iframeRef,
4260
+ src: `${builderBasePath.replace(/\/$/, "")}/${pageID}`,
4261
+ style: { border: "none", height: "100%", width: "100%" },
4262
+ title: "Page Builder"
4263
+ }
4264
+ ) })
4456
4265
  ] }) });
4457
4266
  }
4458
4267
 
4459
- // src/admin/components/studio/AdminStudioNewPageView.tsx
4460
- var import_react19 = require("react");
4461
- var import_ui7 = require("@payloadcms/ui");
4268
+ // src/admin/components/studio/AdminStudioPagesListView.tsx
4462
4269
  var import_jsx_runtime25 = require("react/jsx-runtime");
4463
- var pageTemplates = ["standard", "landing", "services", "contact"];
4270
+ var hasAdminAccess = (user) => {
4271
+ if (!user || typeof user !== "object") return false;
4272
+ const role = user.role;
4273
+ return typeof role === "string" && (role === "admin" || role === "developer");
4274
+ };
4464
4275
  var getPropString5 = (props, key, fallback) => {
4465
4276
  if (!props || typeof props !== "object") return fallback;
4466
4277
  const direct = props[key];
@@ -4472,107 +4283,98 @@ var getPropString5 = (props, key, fallback) => {
4472
4283
  }
4473
4284
  return fallback;
4474
4285
  };
4475
- var canManagePages = (user) => {
4476
- if (!user || typeof user !== "object") return false;
4477
- const role = user.role;
4478
- return role === "admin" || role === "editor";
4479
- };
4480
- var slugify = (value) => value.toLowerCase().trim().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-");
4481
- function AdminStudioNewPageView(props) {
4482
- const { user } = (0, import_ui7.useAuth)();
4286
+ function AdminStudioPagesListView(props) {
4483
4287
  const adminBasePath = useAdminBasePath();
4288
+ const pathname = (0, import_navigation3.usePathname)();
4289
+ const pagesPath = resolveAdminPath(adminBasePath, "/pages");
4290
+ const nestedPagePath = pathname && pathname.startsWith(`${pagesPath}/`) ? pathname.slice(`${pagesPath}/`.length).split("/")[0] : "";
4291
+ if (nestedPagePath === "new") {
4292
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(AdminStudioNewPageView, { ...props });
4293
+ }
4294
+ if (nestedPagePath) {
4295
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(AdminStudioPageEditView, { ...props });
4296
+ }
4297
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(AdminStudioPagesIndexView, { ...props, adminBasePath });
4298
+ }
4299
+ function AdminStudioPagesIndexView({
4300
+ adminBasePath,
4301
+ ...props
4302
+ }) {
4303
+ const { user } = (0, import_ui7.useAuth)();
4484
4304
  const pagesCollectionSlug = getPropString5(props, "pagesCollectionSlug", "pages");
4485
- const [submitting, setSubmitting] = (0, import_react19.useState)(false);
4305
+ const newPagePath = resolveAdminPath(adminBasePath, "/pages/new");
4306
+ const [loading, setLoading] = (0, import_react19.useState)(true);
4486
4307
  const [error, setError] = (0, import_react19.useState)(null);
4487
- if (!canManagePages(user)) {
4488
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4489
- AdminPage,
4490
- {
4491
- breadcrumbs: [
4492
- { label: "Dashboard", href: adminBasePath },
4493
- { label: "Pages", href: resolveAdminPath(adminBasePath, "/pages") },
4494
- { label: "New Page" }
4495
- ],
4496
- description: "You do not have access to create pages.",
4497
- title: "New Page",
4498
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "orion-admin-card", children: [
4499
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("strong", { children: "Access denied" }),
4500
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: "This section is restricted to administrator and editor accounts." })
4501
- ] })
4502
- }
4503
- ) });
4504
- }
4505
- const createPage = async (event) => {
4506
- event.preventDefault();
4507
- setSubmitting(true);
4508
- setError(null);
4509
- try {
4510
- const formData = new FormData(event.currentTarget);
4511
- const titleValue = String(formData.get("title") || "").trim();
4512
- const slugValue = String(formData.get("slug") || "").trim();
4513
- const templateValue = String(formData.get("template") || "standard").trim();
4514
- const template = pageTemplates.includes(templateValue) ? templateValue : "standard";
4515
- const title = titleValue || "Untitled Page";
4516
- const slug = slugValue || slugify(title) || "untitled-page";
4517
- const response = await fetch(`/api/${pagesCollectionSlug}`, {
4518
- body: JSON.stringify({
4519
- _status: "draft",
4520
- slug,
4521
- template,
4522
- title
4523
- }),
4524
- credentials: "include",
4525
- headers: {
4526
- "Content-Type": "application/json"
4527
- },
4528
- method: "POST"
4529
- });
4530
- if (!response.ok) {
4531
- throw new Error(`Failed to create page (${response.status}).`);
4532
- }
4533
- const payload = await response.json();
4534
- const id = typeof payload.id === "string" || typeof payload.id === "number" ? String(payload.id) : "";
4535
- if (!id) {
4536
- throw new Error("Page created but no document ID was returned.");
4308
+ const [docs, setDocs] = (0, import_react19.useState)([]);
4309
+ const apiURL = (0, import_react19.useMemo)(() => {
4310
+ const params = new URLSearchParams({
4311
+ depth: "0",
4312
+ limit: "100",
4313
+ sort: "-updatedAt",
4314
+ draft: "true"
4315
+ });
4316
+ return `/api/${pagesCollectionSlug}?${params.toString()}`;
4317
+ }, [pagesCollectionSlug]);
4318
+ (0, import_react19.useEffect)(() => {
4319
+ let cancelled = false;
4320
+ const run = async () => {
4321
+ setLoading(true);
4322
+ setError(null);
4323
+ try {
4324
+ const res = await fetch(apiURL, { credentials: "include" });
4325
+ if (!res.ok) {
4326
+ const body = await res.text();
4327
+ throw new Error(body || "Failed to fetch pages");
4328
+ }
4329
+ const data = await res.json();
4330
+ if (!cancelled) {
4331
+ setDocs(Array.isArray(data.docs) ? data.docs : []);
4332
+ }
4333
+ } catch (err) {
4334
+ if (!cancelled) {
4335
+ setError(err instanceof Error ? err.message : "Failed to fetch pages");
4336
+ }
4337
+ } finally {
4338
+ if (!cancelled) {
4339
+ setLoading(false);
4340
+ }
4537
4341
  }
4538
- window.location.assign(resolveAdminPath(adminBasePath, `/pages/${id}`));
4539
- } catch (createError) {
4540
- setError(createError instanceof Error ? createError.message : "Failed to create page.");
4541
- } finally {
4542
- setSubmitting(false);
4543
- }
4544
- };
4545
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4342
+ };
4343
+ void run();
4344
+ return () => {
4345
+ cancelled = true;
4346
+ };
4347
+ }, [apiURL]);
4348
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
4546
4349
  AdminPage,
4547
4350
  {
4351
+ actions: hasAdminAccess(user) ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_link2.default, { className: "orion-admin-action-button", href: newPagePath, children: "New Page" }) : null,
4548
4352
  breadcrumbs: [
4549
4353
  { label: "Dashboard", href: adminBasePath },
4550
- { label: "Pages", href: resolveAdminPath(adminBasePath, "/pages") },
4551
- { label: "New Page" }
4354
+ { label: "Pages" }
4552
4355
  ],
4553
- description: "Create a new page and open it in the custom editor.",
4554
- title: "New Page",
4555
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("form", { className: "orion-admin-form", onSubmit: createPage, children: [
4356
+ description: "Open a page to edit it in the inline custom builder.",
4357
+ title: "Pages",
4358
+ children: [
4359
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "orion-admin-list-meta", children: "Loading..." }) : null,
4556
4360
  error ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "orion-admin-error", children: error }) : null,
4557
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("label", { children: [
4558
- "Title",
4559
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("input", { name: "title", placeholder: "Services", required: true, type: "text" })
4560
- ] }),
4561
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("label", { children: [
4562
- "Slug",
4563
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("input", { name: "slug", placeholder: "services", type: "text" })
4564
- ] }),
4565
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("label", { children: [
4566
- "Template",
4567
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("select", { defaultValue: "standard", name: "template", children: [
4568
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("option", { value: "standard", children: "Standard" }),
4569
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("option", { value: "landing", children: "Landing" }),
4570
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("option", { value: "contact", children: "Contact" }),
4571
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("option", { value: "services", children: "Services" })
4572
- ] })
4573
- ] }),
4574
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("button", { disabled: submitting, type: "submit", children: submitting ? "Creating..." : "Create Page" })
4575
- ] })
4361
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "orion-admin-list", children: [
4362
+ !loading && !error && docs.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "orion-admin-card", children: [
4363
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("strong", { children: "No pages yet" }),
4364
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: "Create the first page to start building content." })
4365
+ ] }) : null,
4366
+ docs.map((doc) => {
4367
+ const id = typeof doc.id === "string" || typeof doc.id === "number" ? String(doc.id) : "";
4368
+ if (!id) return null;
4369
+ const title = typeof doc.title === "string" ? doc.title : "Untitled Page";
4370
+ const status = typeof doc._status === "string" ? doc._status : "draft";
4371
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_link2.default, { className: "orion-admin-list-item", href: resolveAdminPath(adminBasePath, `/pages/${id}`), children: [
4372
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("strong", { children: title }) }),
4373
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "orion-admin-pill", children: status })
4374
+ ] }, id);
4375
+ })
4376
+ ] })
4377
+ ]
4576
4378
  }
4577
4379
  ) });
4578
4380
  }
@@ -6841,7 +6643,7 @@ function MediaListItem({
6841
6643
 
6842
6644
  // src/admin-app/components/MediaUploadForm.tsx
6843
6645
  var import_react27 = require("react");
6844
- var import_navigation3 = require("next/navigation");
6646
+ var import_navigation4 = require("next/navigation");
6845
6647
 
6846
6648
  // src/shared/clientImageUploadOptimization.ts
6847
6649
  var MAX_DIRECT_UPLOAD_BYTES = 4e6;
@@ -6976,7 +6778,7 @@ var parseUploadError = async (response) => {
6976
6778
  return fallback;
6977
6779
  };
6978
6780
  function MediaUploadForm() {
6979
- const router = (0, import_navigation3.useRouter)();
6781
+ const router = (0, import_navigation4.useRouter)();
6980
6782
  const fileInputRef = (0, import_react27.useRef)(null);
6981
6783
  const [alt, setAlt] = (0, import_react27.useState)("");
6982
6784
  const [file, setFile] = (0, import_react27.useState)(null);
@@ -7511,17 +7313,17 @@ var FORM_TONE_OVERRIDES = {
7511
7313
  var IDENTITY_KEYS = /* @__PURE__ */ new Set(["contactEmail", "email", "firstName", "lastName", "name"]);
7512
7314
  var RESPONSE_FIELD_PREVIEW_LIMIT = 3;
7513
7315
  var RESPONSE_SCROLL_THRESHOLD = 3;
7514
- var isAdmin3 = (user) => {
7316
+ var hasAdminAccess2 = (user) => {
7515
7317
  if (!user || typeof user !== "object") return false;
7516
7318
  const role = user.role;
7517
- return typeof role === "string" && role === "admin";
7319
+ return typeof role === "string" && (role === "admin" || role === "developer");
7518
7320
  };
7519
- var isEditor2 = (user) => {
7321
+ var isEditor = (user) => {
7520
7322
  if (!user || typeof user !== "object") return false;
7521
7323
  const role = user.role;
7522
7324
  return typeof role === "string" && role === "editor";
7523
7325
  };
7524
- var canReviewForms2 = (user) => isAdmin3(user) || isEditor2(user);
7326
+ var canReviewForms2 = (user) => hasAdminAccess2(user) || isEditor(user);
7525
7327
  var getPropString13 = (props, key, fallback) => {
7526
7328
  if (!props || typeof props !== "object") return fallback;
7527
7329
  const direct = props[key];
@@ -7694,14 +7496,10 @@ function AdminStudioFormsView(props) {
7694
7496
  "formSubmissionsCollectionSlug",
7695
7497
  "form-submissions"
7696
7498
  );
7697
- const formUploadsCollectionSlug = getPropString13(props, "formUploadsCollectionSlug", "form-uploads");
7698
7499
  const adminBasePath = useAdminBasePath();
7699
- const rawFormsPath = resolveAdminPath(adminBasePath, `/collections/${formsCollectionSlug}`);
7700
- const rawSubmissionsPath = resolveAdminPath(
7701
- adminBasePath,
7702
- `/collections/${formSubmissionsCollectionSlug}`
7703
- );
7704
- const rawUploadsPath = resolveAdminPath(adminBasePath, `/collections/${formUploadsCollectionSlug}`);
7500
+ const studioFormsPath = resolveAdminPath(adminBasePath, "/forms");
7501
+ const studioSubmissionsPath = resolveAdminPath(adminBasePath, "/forms/submissions");
7502
+ const studioUploadsPath = resolveAdminPath(adminBasePath, "/forms/uploads");
7705
7503
  const [forms, setForms] = (0, import_react31.useState)([]);
7706
7504
  const [submissions, setSubmissions] = (0, import_react31.useState)([]);
7707
7505
  const [loading, setLoading] = (0, import_react31.useState)(true);
@@ -7861,7 +7659,7 @@ function AdminStudioFormsView(props) {
7861
7659
  import_link3.default,
7862
7660
  {
7863
7661
  className: "orion-admin-action-button orion-admin-action-button--soft",
7864
- href: `${rawFormsPath}/${id}`,
7662
+ href: `${studioFormsPath}/${id}`,
7865
7663
  children: "Open Form"
7866
7664
  }
7867
7665
  )
@@ -7963,7 +7761,7 @@ function AdminStudioFormsView(props) {
7963
7761
  import_link3.default,
7964
7762
  {
7965
7763
  className: "orion-admin-upload-chip",
7966
- href: `${rawUploadsPath}/${uploadID}`,
7764
+ href: `${studioUploadsPath}/${uploadID}`,
7967
7765
  children: uploadLabel
7968
7766
  },
7969
7767
  uploadID
@@ -7980,7 +7778,7 @@ function AdminStudioFormsView(props) {
7980
7778
  import_link3.default,
7981
7779
  {
7982
7780
  className: "orion-admin-action-button orion-admin-action-button--ghost",
7983
- href: `${rawSubmissionsPath}/${submissionID}`,
7781
+ href: `${studioSubmissionsPath}/${submissionID}`,
7984
7782
  children: "Open"
7985
7783
  }
7986
7784
  )
@@ -8000,101 +7798,1728 @@ function AdminStudioFormsView(props) {
8000
7798
  ) });
8001
7799
  }
8002
7800
 
8003
- // src/admin/components/studio/AdminStudioToolsView.tsx
7801
+ // src/admin/components/studio/AdminStudioFormDetailView.tsx
7802
+ var import_link4 = __toESM(require("next/link"));
8004
7803
  var import_react32 = require("react");
8005
- var import_ui12 = require("@payloadcms/ui");
8006
- var import_jsx_runtime41 = require("react/jsx-runtime");
8007
- var userRoles = ["admin", "client", "editor"];
8008
- var isAdmin4 = (user) => {
8009
- if (!user || typeof user !== "object") return false;
8010
- const role = user.role;
8011
- return typeof role === "string" && role === "admin";
7804
+
7805
+ // src/admin/components/studio/formsStudioShared.ts
7806
+ var FORM_TONES2 = [
7807
+ {
7808
+ accent: "var(--orion-cms-tone-1, var(--orion-cms-accent, var(--orion-admin-accent)))",
7809
+ accentBorder: "color-mix(in srgb, var(--orion-cms-tone-1, var(--orion-cms-accent, var(--orion-admin-accent))) 24%, transparent)",
7810
+ accentMist: "color-mix(in srgb, var(--orion-cms-tone-1, var(--orion-cms-accent, var(--orion-admin-accent))) 12%, transparent)",
7811
+ accentSoft: "color-mix(in srgb, var(--orion-cms-tone-1, var(--orion-cms-accent, var(--orion-admin-accent))) 7%, transparent)"
7812
+ },
7813
+ {
7814
+ accent: "var(--orion-cms-tone-2, var(--brand-secondary, var(--orion-admin-accent)))",
7815
+ accentBorder: "color-mix(in srgb, var(--orion-cms-tone-2, var(--brand-secondary, var(--orion-admin-accent))) 24%, transparent)",
7816
+ accentMist: "color-mix(in srgb, var(--orion-cms-tone-2, var(--brand-secondary, var(--orion-admin-accent))) 13%, transparent)",
7817
+ accentSoft: "color-mix(in srgb, var(--orion-cms-tone-2, var(--brand-secondary, var(--orion-admin-accent))) 8%, transparent)"
7818
+ },
7819
+ {
7820
+ accent: "var(--orion-cms-tone-3, color-mix(in srgb, var(--orion-cms-accent, var(--orion-admin-accent)) 72%, #5f816b))",
7821
+ 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)",
7822
+ 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)",
7823
+ 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)"
7824
+ },
7825
+ {
7826
+ accent: "var(--orion-cms-tone-4, color-mix(in srgb, var(--brand-secondary, var(--orion-admin-accent)) 72%, #7a652e))",
7827
+ 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)",
7828
+ 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)",
7829
+ 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)"
7830
+ },
7831
+ {
7832
+ accent: "var(--orion-cms-tone-5, color-mix(in srgb, var(--brand-secondary, var(--orion-admin-accent)) 68%, #8d4a40))",
7833
+ 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)",
7834
+ 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)",
7835
+ 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)"
7836
+ }
7837
+ ];
7838
+ var FORM_TONE_OVERRIDES2 = {
7839
+ "basket-request": FORM_TONES2[1],
7840
+ contact: FORM_TONES2[2],
7841
+ "vendor-inquiry": FORM_TONES2[0]
8012
7842
  };
8013
- var normalizeRole = (value) => userRoles.includes(value) ? value : "editor";
8014
- function AdminStudioToolsView(props) {
8015
- const { user } = (0, import_ui12.useAuth)();
8016
- const adminBasePath = useAdminBasePath();
8017
- const [docs, setDocs] = (0, import_react32.useState)([]);
8018
- const [loading, setLoading] = (0, import_react32.useState)(true);
8019
- const [error, setError] = (0, import_react32.useState)(null);
8020
- const [savedMessage, setSavedMessage] = (0, import_react32.useState)(null);
8021
- const [createSubmitting, setCreateSubmitting] = (0, import_react32.useState)(false);
8022
- const [updatingUserID, setUpdatingUserID] = (0, import_react32.useState)(null);
8023
- if (!isAdmin4(user)) {
8024
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8025
- AdminPage,
8026
- {
8027
- breadcrumbs: [
8028
- { label: "Dashboard", href: adminBasePath },
8029
- { label: "Admin Tools" }
8030
- ],
8031
- description: "You do not have access to this section.",
8032
- title: "Admin Tools",
8033
- children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-card", children: [
8034
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "Access denied" }),
8035
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "This section is restricted to administrator accounts." })
8036
- ] })
8037
- }
8038
- ) });
7843
+ var IDENTITY_KEYS2 = /* @__PURE__ */ new Set(["contactEmail", "email", "firstName", "lastName", "name"]);
7844
+ var RESPONSE_FIELD_PREVIEW_LIMIT2 = 3;
7845
+ var getPropString14 = (props, key, fallback) => {
7846
+ if (!props || typeof props !== "object") return fallback;
7847
+ const direct = props[key];
7848
+ if (typeof direct === "string" && direct.length > 0) return direct;
7849
+ const clientProps = props.clientProps;
7850
+ if (clientProps && typeof clientProps === "object") {
7851
+ const nested = clientProps[key];
7852
+ if (typeof nested === "string" && nested.length > 0) return nested;
8039
7853
  }
8040
- const loadUsers = async () => {
8041
- setLoading(true);
8042
- setError(null);
8043
- try {
8044
- const params = new URLSearchParams({
8045
- depth: "0",
8046
- draft: "true",
8047
- limit: "200",
8048
- sort: "email"
8049
- });
8050
- const response = await fetch(`/api/users?${params.toString()}`, {
8051
- credentials: "include"
8052
- });
8053
- if (!response.ok) {
8054
- throw new Error(`Failed to load users (${response.status}).`);
8055
- }
8056
- const payload = await response.json();
8057
- setDocs(Array.isArray(payload.docs) ? payload.docs : []);
8058
- } catch (loadError) {
8059
- setError(loadError instanceof Error ? loadError.message : "Failed to load users.");
8060
- } finally {
8061
- setLoading(false);
8062
- }
8063
- };
8064
- (0, import_react32.useEffect)(() => {
8065
- void loadUsers();
8066
- }, []);
8067
- const createUser = async (event) => {
8068
- event.preventDefault();
8069
- setCreateSubmitting(true);
8070
- setError(null);
8071
- setSavedMessage(null);
8072
- try {
8073
- const formData = new FormData(event.currentTarget);
8074
- const email = String(formData.get("email") || "").trim();
8075
- const password = String(formData.get("password") || "");
8076
- const fullName = String(formData.get("fullName") || "").trim();
8077
- const role = normalizeRole(String(formData.get("role") || "editor").trim());
8078
- if (!email || !password) {
8079
- throw new Error("Email and password are required.");
8080
- }
8081
- const response = await fetch("/api/users", {
8082
- body: JSON.stringify({
8083
- email,
8084
- fullName,
8085
- password,
8086
- role
8087
- }),
8088
- credentials: "include",
8089
- headers: {
8090
- "Content-Type": "application/json"
8091
- },
8092
- method: "POST"
8093
- });
7854
+ return fallback;
7855
+ };
7856
+ var getParam3 = (params, key) => {
7857
+ if (!params || typeof params !== "object") return null;
7858
+ const value = params[key];
7859
+ if (typeof value === "string") return value;
7860
+ if (Array.isArray(value) && typeof value[0] === "string") return value[0];
7861
+ return null;
7862
+ };
7863
+ var getIDFromPathname = (pathname, marker) => {
7864
+ const markerIndex = pathname.indexOf(marker);
7865
+ if (markerIndex < 0) return null;
7866
+ const id = pathname.slice(markerIndex + marker.length).split("/")[0];
7867
+ return id ? decodeURIComponent(id) : null;
7868
+ };
7869
+ var formatDate2 = (value) => {
7870
+ if (typeof value !== "string" || value.length === 0) return "Unknown date";
7871
+ const date = new Date(value);
7872
+ if (Number.isNaN(date.getTime())) return value;
7873
+ return date.toLocaleString();
7874
+ };
7875
+ var formatFileSize4 = (value) => {
7876
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return null;
7877
+ if (value < 1024) return `${value} B`;
7878
+ if (value < 1024 * 1024) return `${(value / 1024).toFixed(1)} KB`;
7879
+ return `${(value / (1024 * 1024)).toFixed(1)} MB`;
7880
+ };
7881
+ var getFieldCount2 = (form) => Array.isArray(form.steps) ? form.steps.reduce((count, step) => {
7882
+ if (!step || typeof step !== "object") return count;
7883
+ const fields = step.fields;
7884
+ return count + (Array.isArray(fields) ? fields.length : 0);
7885
+ }, 0) : 0;
7886
+ var getFormID3 = (value) => {
7887
+ if (typeof value === "string" || typeof value === "number") return String(value);
7888
+ if (value && typeof value === "object") {
7889
+ const id = value.id;
7890
+ if (typeof id === "string" || typeof id === "number") return String(id);
7891
+ }
7892
+ return "";
7893
+ };
7894
+ var getUploads2 = (value) => Array.isArray(value) ? value.map((entry) => {
7895
+ if (typeof entry === "string" || typeof entry === "number") {
7896
+ return { id: entry };
7897
+ }
7898
+ return entry && typeof entry === "object" ? entry : null;
7899
+ }).filter((entry) => Boolean(entry)) : [];
7900
+ var getNameAndEmail2 = (data) => {
7901
+ if (!data || typeof data !== "object") return {};
7902
+ const record = data;
7903
+ const email = typeof record.email === "string" ? record.email : typeof record.contactEmail === "string" ? record.contactEmail : void 0;
7904
+ const firstName = typeof record.firstName === "string" ? record.firstName : void 0;
7905
+ const lastName = typeof record.lastName === "string" ? record.lastName : void 0;
7906
+ const fallbackName = typeof record.name === "string" ? record.name : void 0;
7907
+ const joinedName = [firstName, lastName].filter(Boolean).join(" ").trim();
7908
+ return {
7909
+ ...email ? { email } : {},
7910
+ ...joinedName ? { name: joinedName } : fallbackName ? { name: fallbackName } : {}
7911
+ };
7912
+ };
7913
+ var humanizeKey2 = (value) => value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim().replace(/^./, (char) => char.toUpperCase());
7914
+ var buildFieldLabelMap2 = (form) => {
7915
+ const labels = /* @__PURE__ */ new Map();
7916
+ for (const step of Array.isArray(form.steps) ? form.steps : []) {
7917
+ const fields = step && typeof step === "object" ? step.fields : null;
7918
+ for (const field of Array.isArray(fields) ? fields : []) {
7919
+ const name = field && typeof field === "object" && typeof field.name === "string" ? field.name.trim() : "";
7920
+ const label = field && typeof field === "object" && typeof field.label === "string" ? field.label.trim() : "";
7921
+ if (name) {
7922
+ labels.set(name, label || humanizeKey2(name));
7923
+ }
7924
+ }
7925
+ }
7926
+ return labels;
7927
+ };
7928
+ var truncateText2 = (value, maxLength = 64) => {
7929
+ const normalized = value.replace(/\s+/g, " ").trim();
7930
+ if (normalized.length <= maxLength) return normalized;
7931
+ return `${normalized.slice(0, maxLength - 1).trimEnd()}...`;
7932
+ };
7933
+ var formatPreviewValue2 = (value) => {
7934
+ if (value === null || value === void 0) return null;
7935
+ if (typeof value === "boolean") return value ? "Yes" : "No";
7936
+ if (typeof value === "number") return String(value);
7937
+ if (typeof value === "string") {
7938
+ const trimmed = value.trim();
7939
+ return trimmed ? truncateText2(trimmed, 72) : null;
7940
+ }
7941
+ if (Array.isArray(value)) {
7942
+ const joined = value.map((entry) => String(entry).trim()).filter(Boolean).join(", ");
7943
+ return joined ? truncateText2(joined, 72) : null;
7944
+ }
7945
+ if (typeof value === "object") {
7946
+ return truncateText2(JSON.stringify(value), 72);
7947
+ }
7948
+ return truncateText2(String(value), 72);
7949
+ };
7950
+ var getPreviewFields2 = (data, fieldLabels) => {
7951
+ if (!data || typeof data !== "object") return [];
7952
+ return Object.entries(data).filter(([key]) => !IDENTITY_KEYS2.has(key)).map(([key, value]) => {
7953
+ const formatted = formatPreviewValue2(value);
7954
+ if (!formatted) return null;
7955
+ return {
7956
+ label: fieldLabels.get(key) || humanizeKey2(key),
7957
+ value: formatted
7958
+ };
7959
+ }).filter((entry) => Boolean(entry)).slice(0, RESPONSE_FIELD_PREVIEW_LIMIT2);
7960
+ };
7961
+ var getInitials3 = (...values) => {
7962
+ const source = values.find((value) => typeof value === "string" && value.trim().length > 0);
7963
+ if (!source) return "FM";
7964
+ const cleaned = source.replace(/[^a-z0-9]+/gi, " ").trim();
7965
+ if (!cleaned) return "FM";
7966
+ const parts = cleaned.split(/\s+/).filter(Boolean);
7967
+ if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
7968
+ return `${parts[0][0] || ""}${parts[1][0] || ""}`.toUpperCase();
7969
+ };
7970
+ var getHash2 = (value) => {
7971
+ let hash = 0;
7972
+ for (let index = 0; index < value.length; index += 1) {
7973
+ hash = hash * 31 + value.charCodeAt(index) >>> 0;
7974
+ }
7975
+ return hash;
7976
+ };
7977
+ var normalizeToneKey2 = (value) => value?.trim().toLowerCase() || "";
7978
+ var getFormTone2 = (slug, fallbackSeed) => {
7979
+ const normalizedSlug = normalizeToneKey2(slug);
7980
+ if (normalizedSlug && FORM_TONE_OVERRIDES2[normalizedSlug]) {
7981
+ return FORM_TONE_OVERRIDES2[normalizedSlug];
7982
+ }
7983
+ const normalizedSeed = normalizeToneKey2(fallbackSeed);
7984
+ if (normalizedSeed && FORM_TONE_OVERRIDES2[normalizedSeed]) {
7985
+ return FORM_TONE_OVERRIDES2[normalizedSeed];
7986
+ }
7987
+ return FORM_TONES2[getHash2(slug || fallbackSeed) % FORM_TONES2.length];
7988
+ };
7989
+ var getFormToneStyle2 = (slug, fallbackSeed) => {
7990
+ const tone = getFormTone2(slug, fallbackSeed);
7991
+ return {
7992
+ ["--form-accent"]: tone.accent,
7993
+ ["--form-accent-border"]: tone.accentBorder,
7994
+ ["--form-accent-mist"]: tone.accentMist,
7995
+ ["--form-accent-soft"]: tone.accentSoft
7996
+ };
7997
+ };
7998
+ var getFormTitle2 = (value) => {
7999
+ if (value && typeof value === "object" && typeof value.title === "string") {
8000
+ const title = value.title.trim();
8001
+ if (title.length > 0) return title;
8002
+ }
8003
+ if (typeof value === "string" && value.trim().length > 0) {
8004
+ return value;
8005
+ }
8006
+ return "Untitled Form";
8007
+ };
8008
+
8009
+ // src/admin/components/studio/AdminStudioFormDetailView.tsx
8010
+ var import_jsx_runtime41 = require("react/jsx-runtime");
8011
+ var getNonEmptyText = (value, fallback = "") => typeof value === "string" && value.trim().length > 0 ? value : fallback;
8012
+ var normalizeSteps = (value) => {
8013
+ if (!Array.isArray(value)) {
8014
+ return [];
8015
+ }
8016
+ return value.map((step) => step && typeof step === "object" && !Array.isArray(step) ? step : {});
8017
+ };
8018
+ var normalizeFormResponse = (value) => {
8019
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
8020
+ return {};
8021
+ }
8022
+ const record = value;
8023
+ const nestedDoc = record.doc;
8024
+ if (nestedDoc && typeof nestedDoc === "object" && !Array.isArray(nestedDoc)) {
8025
+ return nestedDoc;
8026
+ }
8027
+ return record;
8028
+ };
8029
+ var toEditorState = (doc) => {
8030
+ const emails = doc.emails && typeof doc.emails === "object" ? doc.emails : null;
8031
+ const adminRecipients = Array.isArray(emails?.adminRecipients) ? emails?.adminRecipients.map(
8032
+ (entry) => entry && typeof entry === "object" && typeof entry.email === "string" ? entry.email.trim() : ""
8033
+ ).filter(Boolean) : [];
8034
+ return {
8035
+ adminRecipientsText: adminRecipients.join("\n"),
8036
+ adminSubject: getNonEmptyText(emails?.adminSubject),
8037
+ confirmationHeading: getNonEmptyText(emails?.confirmationHeading),
8038
+ confirmationMessage: getNonEmptyText(emails?.confirmationMessage),
8039
+ confirmationSubject: getNonEmptyText(emails?.confirmationSubject),
8040
+ sendAdmin: emails?.sendAdmin !== false,
8041
+ sendConfirmation: emails?.sendConfirmation !== false,
8042
+ slug: getNonEmptyText(doc.slug),
8043
+ steps: normalizeSteps(doc.steps),
8044
+ submitLabel: getNonEmptyText(doc.submitLabel, "Submit"),
8045
+ successMessage: getNonEmptyText(doc.successMessage),
8046
+ title: getNonEmptyText(doc.title, "Untitled Form")
8047
+ };
8048
+ };
8049
+ var checkboxLabelStyle = {
8050
+ alignItems: "center",
8051
+ display: "flex",
8052
+ gap: "0.6rem"
8053
+ };
8054
+ var sectionGridStyle = {
8055
+ display: "grid",
8056
+ gap: "1rem",
8057
+ gridTemplateColumns: "repeat(auto-fit, minmax(320px, 1fr))"
8058
+ };
8059
+ var fieldTypeOptions = [
8060
+ "text",
8061
+ "textarea",
8062
+ "email",
8063
+ "phone",
8064
+ "url",
8065
+ "select",
8066
+ "radio",
8067
+ "checkbox",
8068
+ "checkbox-group",
8069
+ "date",
8070
+ "file"
8071
+ ];
8072
+ var getFields = (step) => Array.isArray(step.fields) ? step.fields.map(
8073
+ (field) => field && typeof field === "object" && !Array.isArray(field) ? field : {}
8074
+ ) : [];
8075
+ var toOptionsText = (value) => Array.isArray(value) ? value.map((entry) => {
8076
+ if (entry && typeof entry === "object" && !Array.isArray(entry)) {
8077
+ const record = entry;
8078
+ const label = typeof record.label === "string" ? record.label : "";
8079
+ const optionValue = typeof record.value === "string" ? record.value : label;
8080
+ return label && optionValue && label !== optionValue ? `${label} | ${optionValue}` : label || optionValue;
8081
+ }
8082
+ return typeof entry === "string" ? entry : "";
8083
+ }).filter(Boolean).join("\n") : "";
8084
+ var fromOptionsText = (value) => value.split("\n").map((entry) => entry.trim()).filter(Boolean).map((entry) => {
8085
+ const [label, optionValue] = entry.split("|").map((part) => part.trim());
8086
+ return {
8087
+ label,
8088
+ value: optionValue || label
8089
+ };
8090
+ });
8091
+ var slugifyFieldName = (value) => value.trim().replace(/[^a-z0-9]+/gi, " ").trim().replace(/\s+([a-z0-9])/gi, (_, char) => char.toUpperCase()).replace(/^./, (char) => char.toLowerCase());
8092
+ var blankField = () => ({
8093
+ label: "New field",
8094
+ name: "newField",
8095
+ required: false,
8096
+ type: "text"
8097
+ });
8098
+ var blankStep = () => ({
8099
+ fields: [blankField()],
8100
+ title: "New step"
8101
+ });
8102
+ var getStepTitle = (step, stepIndex) => getNonEmptyText(step.title, `Step ${stepIndex + 1}`);
8103
+ var getFieldLabel = (field, fieldIndex) => getNonEmptyText(field.label, getNonEmptyText(field.name, `Field ${fieldIndex + 1}`));
8104
+ var formatFieldTypeLabel = (value) => getNonEmptyText(value, "text").replace(/-/g, " ").replace(/^./, (char) => char.toUpperCase());
8105
+ var getStepDestination = (stepIndex, stepCount) => {
8106
+ if (stepIndex < stepCount - 1) {
8107
+ return `Next: Step ${stepIndex + 2}`;
8108
+ }
8109
+ return "Then: Submit form";
8110
+ };
8111
+ var moveItem = (items, fromIndex, toIndex) => {
8112
+ if (toIndex < 0 || toIndex >= items.length) {
8113
+ return items;
8114
+ }
8115
+ const nextItems = [...items];
8116
+ const [item] = nextItems.splice(fromIndex, 1);
8117
+ nextItems.splice(toIndex, 0, item);
8118
+ return nextItems;
8119
+ };
8120
+ function getFormIDFromPathname(pathname) {
8121
+ const marker = "/forms/";
8122
+ const raw = getIDFromPathname(pathname, marker);
8123
+ if (!raw || raw === "submissions" || raw === "uploads") {
8124
+ return null;
8125
+ }
8126
+ return raw;
8127
+ }
8128
+ function AdminStudioFormDetailView(props) {
8129
+ const formsCollectionSlug = getPropString14(props, "formsCollectionSlug", "forms");
8130
+ const formSubmissionsCollectionSlug = getPropString14(
8131
+ props,
8132
+ "formSubmissionsCollectionSlug",
8133
+ "form-submissions"
8134
+ );
8135
+ const adminBasePath = useAdminBasePath();
8136
+ const formsPath = resolveAdminPath(adminBasePath, "/forms");
8137
+ const formIDFromParams = (0, import_react32.useMemo)(() => getParam3(props.params, "id"), [props.params]);
8138
+ const [formID, setFormID] = (0, import_react32.useState)(formIDFromParams);
8139
+ const [didResolvePathFallback, setDidResolvePathFallback] = (0, import_react32.useState)(false);
8140
+ const [doc, setDoc] = (0, import_react32.useState)(null);
8141
+ const [submissions, setSubmissions] = (0, import_react32.useState)([]);
8142
+ const [editorState, setEditorState] = (0, import_react32.useState)(null);
8143
+ const [loading, setLoading] = (0, import_react32.useState)(true);
8144
+ const [error, setError] = (0, import_react32.useState)(null);
8145
+ const [saving, setSaving] = (0, import_react32.useState)(false);
8146
+ const [savedMessage, setSavedMessage] = (0, import_react32.useState)(null);
8147
+ (0, import_react32.useEffect)(() => {
8148
+ if (formIDFromParams) {
8149
+ setFormID(formIDFromParams);
8150
+ setDidResolvePathFallback(true);
8151
+ return;
8152
+ }
8153
+ if (typeof window !== "undefined") {
8154
+ setFormID(getFormIDFromPathname(window.location.pathname));
8155
+ }
8156
+ setDidResolvePathFallback(true);
8157
+ }, [formIDFromParams]);
8158
+ const loadDoc = async (id) => {
8159
+ setLoading(true);
8160
+ setError(null);
8161
+ try {
8162
+ const submissionsParams = new URLSearchParams({
8163
+ depth: "1",
8164
+ limit: "25",
8165
+ sort: "-submittedAt"
8166
+ });
8167
+ submissionsParams.set("where[form][equals]", id);
8168
+ const [formResponse, submissionsResponse] = await Promise.all([
8169
+ fetch(`/api/${formsCollectionSlug}/${encodeURIComponent(id)}?depth=0&draft=true`, {
8170
+ credentials: "include"
8171
+ }),
8172
+ fetch(`/api/${formSubmissionsCollectionSlug}?${submissionsParams.toString()}`, {
8173
+ credentials: "include"
8174
+ })
8175
+ ]);
8176
+ if (!formResponse.ok) {
8177
+ throw new Error(`Failed to load form (${formResponse.status}).`);
8178
+ }
8179
+ if (!submissionsResponse.ok) {
8180
+ throw new Error(`Failed to load submissions (${submissionsResponse.status}).`);
8181
+ }
8182
+ const nextDoc = normalizeFormResponse(await formResponse.json());
8183
+ const submissionsPayload = await submissionsResponse.json();
8184
+ const nextSubmissions = Array.isArray(submissionsPayload.docs) ? submissionsPayload.docs : [];
8185
+ setDoc(nextDoc);
8186
+ setEditorState(toEditorState(nextDoc));
8187
+ setSubmissions(nextSubmissions);
8188
+ } catch (loadError) {
8189
+ setError(loadError instanceof Error ? loadError.message : "Failed to load form.");
8190
+ setDoc(null);
8191
+ setEditorState(null);
8192
+ setSubmissions([]);
8193
+ } finally {
8194
+ setLoading(false);
8195
+ }
8196
+ };
8197
+ (0, import_react32.useEffect)(() => {
8198
+ if (!formID) {
8199
+ return;
8200
+ }
8201
+ void loadDoc(formID);
8202
+ }, [formID, formsCollectionSlug, formSubmissionsCollectionSlug]);
8203
+ const save = async (event) => {
8204
+ event.preventDefault();
8205
+ if (!formID || !editorState) {
8206
+ return;
8207
+ }
8208
+ setSaving(true);
8209
+ setError(null);
8210
+ setSavedMessage(null);
8211
+ try {
8212
+ const payload = {
8213
+ emails: {
8214
+ adminRecipients: editorState.adminRecipientsText.split("\n").map((value) => value.trim()).filter(Boolean).map((email) => ({ email })),
8215
+ adminSubject: editorState.adminSubject.trim(),
8216
+ confirmationHeading: editorState.confirmationHeading.trim(),
8217
+ confirmationMessage: editorState.confirmationMessage,
8218
+ confirmationSubject: editorState.confirmationSubject.trim(),
8219
+ sendAdmin: editorState.sendAdmin,
8220
+ sendConfirmation: editorState.sendConfirmation
8221
+ },
8222
+ slug: editorState.slug.trim(),
8223
+ steps: editorState.steps,
8224
+ submitLabel: editorState.submitLabel.trim(),
8225
+ successMessage: editorState.successMessage,
8226
+ title: editorState.title.trim()
8227
+ };
8228
+ const response = await fetch(`/api/${formsCollectionSlug}/${encodeURIComponent(formID)}`, {
8229
+ body: JSON.stringify(payload),
8230
+ credentials: "include",
8231
+ headers: {
8232
+ "Content-Type": "application/json"
8233
+ },
8234
+ method: "PATCH"
8235
+ });
8236
+ if (!response.ok) {
8237
+ throw new Error(`Failed to save form (${response.status}).`);
8238
+ }
8239
+ const nextDoc = normalizeFormResponse(await response.json());
8240
+ setDoc(nextDoc);
8241
+ setEditorState(toEditorState(nextDoc));
8242
+ setSavedMessage("Saved.");
8243
+ } catch (saveError) {
8244
+ setError(saveError instanceof Error ? saveError.message : "Failed to save form.");
8245
+ } finally {
8246
+ setSaving(false);
8247
+ }
8248
+ };
8249
+ if (!formID && !didResolvePathFallback) {
8250
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8251
+ AdminPage,
8252
+ {
8253
+ breadcrumbs: [
8254
+ { label: "Dashboard", href: adminBasePath },
8255
+ { label: "Forms", href: formsPath },
8256
+ { label: "Form" }
8257
+ ],
8258
+ description: "Loading form workspace...",
8259
+ title: "Form",
8260
+ children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_jsx_runtime41.Fragment, {})
8261
+ }
8262
+ ) });
8263
+ }
8264
+ const title = doc && typeof doc.title === "string" && doc.title.trim().length > 0 ? doc.title : "Form";
8265
+ const slug = doc && typeof doc.slug === "string" ? doc.slug : "";
8266
+ const toneStyle = getFormToneStyle2(slug, title || formID || "form");
8267
+ const fieldLabels = doc ? buildFieldLabelMap2(doc) : /* @__PURE__ */ new Map();
8268
+ const latestSubmission = submissions[0];
8269
+ const stepCount = editorState?.steps.length || 0;
8270
+ const fieldCount = editorState ? editorState.steps.reduce((count, step) => count + getFields(step).length, 0) : doc ? getFieldCount2(doc) : 0;
8271
+ const updateStep = (stepIndex, patch) => {
8272
+ setEditorState(
8273
+ (current) => current ? {
8274
+ ...current,
8275
+ steps: current.steps.map(
8276
+ (step, index) => index === stepIndex ? { ...step, ...patch } : step
8277
+ )
8278
+ } : current
8279
+ );
8280
+ };
8281
+ const updateField = (stepIndex, fieldIndex, patch) => {
8282
+ setEditorState((current) => {
8283
+ if (!current) return current;
8284
+ return {
8285
+ ...current,
8286
+ steps: current.steps.map((step, index) => {
8287
+ if (index !== stepIndex) return step;
8288
+ const fields = getFields(step).map(
8289
+ (field, currentFieldIndex) => currentFieldIndex === fieldIndex ? { ...field, ...patch } : field
8290
+ );
8291
+ return { ...step, fields };
8292
+ })
8293
+ };
8294
+ });
8295
+ };
8296
+ const moveStep = (stepIndex, direction) => {
8297
+ setEditorState(
8298
+ (current) => current ? {
8299
+ ...current,
8300
+ steps: moveItem(current.steps, stepIndex, stepIndex + direction)
8301
+ } : current
8302
+ );
8303
+ };
8304
+ const moveField = (stepIndex, fieldIndex, direction) => {
8305
+ setEditorState((current) => {
8306
+ if (!current) return current;
8307
+ return {
8308
+ ...current,
8309
+ steps: current.steps.map(
8310
+ (step, index) => index === stepIndex ? { ...step, fields: moveItem(getFields(step), fieldIndex, fieldIndex + direction) } : step
8311
+ )
8312
+ };
8313
+ });
8314
+ };
8315
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
8316
+ AdminPage,
8317
+ {
8318
+ breadcrumbs: [
8319
+ { label: "Dashboard", href: adminBasePath },
8320
+ { label: "Forms", href: formsPath },
8321
+ { label: title }
8322
+ ],
8323
+ description: "Manage form content and review recent responses without leaving Studio.",
8324
+ title: "Form",
8325
+ children: [
8326
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-list-meta", children: "Loading..." }) : null,
8327
+ error ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-error", children: error }) : null,
8328
+ savedMessage ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-success", children: savedMessage }) : null,
8329
+ !loading && !error && doc && editorState && formID ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { style: { display: "grid", gap: "1rem" }, children: [
8330
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-forms-summary-grid", children: [
8331
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("article", { className: "orion-admin-overview-stat", children: [
8332
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-overview-stat-label", children: "Workflow steps" }),
8333
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: stepCount }),
8334
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { children: "Configured stages in the public form flow." })
8335
+ ] }),
8336
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("article", { className: "orion-admin-overview-stat", children: [
8337
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-overview-stat-label", children: "Fields" }),
8338
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: fieldCount }),
8339
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { children: "Total visible and conditional fields across every step." })
8340
+ ] }),
8341
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("article", { className: "orion-admin-overview-stat", children: [
8342
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-overview-stat-label", children: "Recent submissions" }),
8343
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: submissions.length }),
8344
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { children: latestSubmission ? `Latest response ${formatDate2(latestSubmission.submittedAt)}` : "No responses have been recorded yet." })
8345
+ ] })
8346
+ ] }),
8347
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("section", { className: "orion-admin-form-board", style: toneStyle, children: [
8348
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-form-board-header", children: [
8349
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-form-board-heading", children: [
8350
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-form-board-kicker-row", children: [
8351
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-form-board-kicker", children: slug || "No slug set" }),
8352
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-form-board-meta", children: doc.updatedAt ? `Updated ${formatDate2(doc.updatedAt)}` : "Update time unavailable" })
8353
+ ] }),
8354
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-form-board-title-row", children: [
8355
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-form-board-mark", children: getInitials3(title, slug) }),
8356
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-form-board-copy", children: [
8357
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("h2", { className: "orion-admin-form-board-title", children: title }),
8358
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "orion-admin-form-board-subtitle", children: editorState.successMessage.trim().length > 0 ? editorState.successMessage : "No success message set." })
8359
+ ] })
8360
+ ] })
8361
+ ] }),
8362
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-form-board-actions", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-form-board-count", children: [
8363
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-form-board-count-value", children: submissions.length }),
8364
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "orion-admin-form-board-count-label", children: [
8365
+ "response",
8366
+ submissions.length === 1 ? "" : "s"
8367
+ ] })
8368
+ ] }) })
8369
+ ] }),
8370
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-form-board-metrics", children: [
8371
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("article", { className: "orion-admin-form-metric", children: [
8372
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-form-metric-label", children: "Submit button" }),
8373
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { className: "orion-admin-form-metric-value is-copy", children: editorState.submitLabel || "Submit" })
8374
+ ] }),
8375
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("article", { className: "orion-admin-form-metric", children: [
8376
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-form-metric-label", children: "Admin notifications" }),
8377
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { className: "orion-admin-form-metric-value", children: editorState.sendAdmin ? "On" : "Off" })
8378
+ ] }),
8379
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("article", { className: "orion-admin-form-metric", children: [
8380
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-form-metric-label", children: "Confirmation email" }),
8381
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { className: "orion-admin-form-metric-value", children: editorState.sendConfirmation ? "On" : "Off" })
8382
+ ] }),
8383
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("article", { className: "orion-admin-form-metric", children: [
8384
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-form-metric-label", children: "Latest response" }),
8385
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { className: "orion-admin-form-metric-value is-copy", children: latestSubmission ? formatDate2(latestSubmission.submittedAt) : "No activity yet" })
8386
+ ] })
8387
+ ] })
8388
+ ] }),
8389
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { style: sectionGridStyle, children: [
8390
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { style: { display: "grid", gap: "1rem" }, children: [
8391
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-card", children: [
8392
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "Step preview" }),
8393
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "Review the public workflow as visitors will move through it." }),
8394
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { style: { display: "grid", gap: "0.85rem", marginTop: "1rem" }, children: editorState.steps.length > 0 ? editorState.steps.map((record, stepIndex) => {
8395
+ const fields = getFields(record);
8396
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-form", children: [
8397
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { children: [
8398
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("strong", { children: [
8399
+ "Step ",
8400
+ stepIndex + 1,
8401
+ ": ",
8402
+ getNonEmptyText(record?.title, "Untitled Step")
8403
+ ] }),
8404
+ getNonEmptyText(record?.subtitle) ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-list-meta", style: { marginTop: "0.25rem" }, children: getNonEmptyText(record?.subtitle) }) : null
8405
+ ] }),
8406
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-inline-actions", children: [
8407
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "orion-admin-pill", children: [
8408
+ fields.length,
8409
+ " field",
8410
+ fields.length === 1 ? "" : "s"
8411
+ ] }),
8412
+ record?.allowSkip === true ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-pill", children: "Can skip" }) : null,
8413
+ getNonEmptyText(record?.nextLabel) ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "orion-admin-pill", children: [
8414
+ "Next: ",
8415
+ getNonEmptyText(record?.nextLabel)
8416
+ ] }) : null
8417
+ ] }),
8418
+ fields.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-list", children: fields.map((field, fieldIndex) => {
8419
+ const fieldRecord = field && typeof field === "object" && !Array.isArray(field) ? field : null;
8420
+ const type = getNonEmptyText(fieldRecord?.type, "text");
8421
+ const label = getNonEmptyText(
8422
+ fieldRecord?.label,
8423
+ getNonEmptyText(fieldRecord?.name, `Field ${fieldIndex + 1}`)
8424
+ );
8425
+ const helpText = getNonEmptyText(fieldRecord?.helpText);
8426
+ const condition = fieldRecord?.condition && typeof fieldRecord.condition === "object" && !Array.isArray(fieldRecord.condition) ? fieldRecord.condition : null;
8427
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-list-item", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { children: [
8428
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: label }),
8429
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-list-meta", children: [
8430
+ type,
8431
+ fieldRecord?.required === true ? " \xB7 required" : "",
8432
+ condition?.field && condition?.equals ? ` \xB7 when ${String(condition.field)} = ${String(condition.equals)}` : ""
8433
+ ] }),
8434
+ helpText ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8435
+ "div",
8436
+ {
8437
+ className: "orion-admin-list-meta",
8438
+ style: { marginTop: "0.25rem" },
8439
+ children: helpText
8440
+ }
8441
+ ) : null
8442
+ ] }) }, `field-${fieldIndex}`);
8443
+ }) }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-list-meta", children: "This step has no fields." })
8444
+ ] }, `step-${stepIndex}`);
8445
+ }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-empty-state", children: [
8446
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "No steps configured" }),
8447
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "Add at least one step in Form settings to publish this form." })
8448
+ ] }) })
8449
+ ] }),
8450
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-card", children: [
8451
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "Recent submissions" }),
8452
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "Jump from the form definition into the latest responses." }),
8453
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { style: { display: "grid", gap: "0.85rem", marginTop: "1rem" }, children: submissions.length > 0 ? submissions.map((submission) => {
8454
+ const submissionID = typeof submission.id === "string" || typeof submission.id === "number" ? String(submission.id) : "";
8455
+ if (!submissionID) return null;
8456
+ const identity = getNameAndEmail2(submission.data);
8457
+ const previewFields = getPreviewFields2(submission.data, fieldLabels);
8458
+ const formSubmissionPath = resolveAdminPath(
8459
+ adminBasePath,
8460
+ `/forms/submissions/${submissionID}`
8461
+ );
8462
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_link4.default, { className: "orion-admin-list-item", href: formSubmissionPath, children: [
8463
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { children: [
8464
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: identity.name || identity.email || "Submission" }),
8465
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-list-meta", children: formatDate2(submission.submittedAt) }),
8466
+ previewFields.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-list-meta", style: { marginTop: "0.3rem" }, children: previewFields.map((field) => `${field.label}: ${field.value}`).join(" \xB7 ") }) : null
8467
+ ] }),
8468
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-action-button orion-admin-action-button--ghost", children: "Open" })
8469
+ ] }, submissionID);
8470
+ }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-empty-state", children: [
8471
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "No responses yet" }),
8472
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "This view will populate as soon as the form starts receiving traffic." })
8473
+ ] }) })
8474
+ ] })
8475
+ ] }),
8476
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("form", { className: "orion-admin-form", onSubmit: save, children: [
8477
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "Form settings" }),
8478
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8479
+ "Title",
8480
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8481
+ "input",
8482
+ {
8483
+ onChange: (event) => setEditorState(
8484
+ (current) => current ? { ...current, title: event.target.value } : current
8485
+ ),
8486
+ required: true,
8487
+ type: "text",
8488
+ value: editorState.title
8489
+ }
8490
+ )
8491
+ ] }),
8492
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8493
+ "Slug",
8494
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8495
+ "input",
8496
+ {
8497
+ onChange: (event) => setEditorState(
8498
+ (current) => current ? { ...current, slug: event.target.value } : current
8499
+ ),
8500
+ required: true,
8501
+ type: "text",
8502
+ value: editorState.slug
8503
+ }
8504
+ )
8505
+ ] }),
8506
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8507
+ "Submit button",
8508
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8509
+ "input",
8510
+ {
8511
+ onChange: (event) => setEditorState(
8512
+ (current) => current ? { ...current, submitLabel: event.target.value } : current
8513
+ ),
8514
+ type: "text",
8515
+ value: editorState.submitLabel
8516
+ }
8517
+ )
8518
+ ] }),
8519
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8520
+ "Success message",
8521
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8522
+ "textarea",
8523
+ {
8524
+ onChange: (event) => setEditorState(
8525
+ (current) => current ? { ...current, successMessage: event.target.value } : current
8526
+ ),
8527
+ rows: 4,
8528
+ value: editorState.successMessage
8529
+ }
8530
+ )
8531
+ ] }),
8532
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-card", children: [
8533
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "Email behavior" }),
8534
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { style: { display: "grid", gap: "0.85rem", marginTop: "0.9rem" }, children: [
8535
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { style: checkboxLabelStyle, children: [
8536
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8537
+ "input",
8538
+ {
8539
+ checked: editorState.sendAdmin,
8540
+ onChange: (event) => setEditorState(
8541
+ (current) => current ? { ...current, sendAdmin: event.target.checked } : current
8542
+ ),
8543
+ type: "checkbox"
8544
+ }
8545
+ ),
8546
+ "Send admin notifications"
8547
+ ] }),
8548
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8549
+ "Admin recipients",
8550
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8551
+ "textarea",
8552
+ {
8553
+ onChange: (event) => setEditorState(
8554
+ (current) => current ? { ...current, adminRecipientsText: event.target.value } : current
8555
+ ),
8556
+ placeholder: "one@email.com\ntwo@email.com",
8557
+ rows: 4,
8558
+ value: editorState.adminRecipientsText
8559
+ }
8560
+ )
8561
+ ] }),
8562
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8563
+ "Admin subject",
8564
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8565
+ "input",
8566
+ {
8567
+ onChange: (event) => setEditorState(
8568
+ (current) => current ? { ...current, adminSubject: event.target.value } : current
8569
+ ),
8570
+ type: "text",
8571
+ value: editorState.adminSubject
8572
+ }
8573
+ )
8574
+ ] }),
8575
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { style: checkboxLabelStyle, children: [
8576
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8577
+ "input",
8578
+ {
8579
+ checked: editorState.sendConfirmation,
8580
+ onChange: (event) => setEditorState(
8581
+ (current) => current ? { ...current, sendConfirmation: event.target.checked } : current
8582
+ ),
8583
+ type: "checkbox"
8584
+ }
8585
+ ),
8586
+ "Send confirmation email"
8587
+ ] }),
8588
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8589
+ "Confirmation subject",
8590
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8591
+ "input",
8592
+ {
8593
+ onChange: (event) => setEditorState(
8594
+ (current) => current ? { ...current, confirmationSubject: event.target.value } : current
8595
+ ),
8596
+ type: "text",
8597
+ value: editorState.confirmationSubject
8598
+ }
8599
+ )
8600
+ ] }),
8601
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8602
+ "Confirmation heading",
8603
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8604
+ "input",
8605
+ {
8606
+ onChange: (event) => setEditorState(
8607
+ (current) => current ? { ...current, confirmationHeading: event.target.value } : current
8608
+ ),
8609
+ type: "text",
8610
+ value: editorState.confirmationHeading
8611
+ }
8612
+ )
8613
+ ] }),
8614
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8615
+ "Confirmation message",
8616
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8617
+ "textarea",
8618
+ {
8619
+ onChange: (event) => setEditorState(
8620
+ (current) => current ? { ...current, confirmationMessage: event.target.value } : current
8621
+ ),
8622
+ rows: 4,
8623
+ value: editorState.confirmationMessage
8624
+ }
8625
+ )
8626
+ ] })
8627
+ ] })
8628
+ ] }),
8629
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-card orion-admin-workflow-editor", children: [
8630
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-workflow-editor-header", children: [
8631
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { children: [
8632
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "Form steps" }),
8633
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "Build the visitor flow, then edit each step's fields below." })
8634
+ ] }),
8635
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8636
+ "button",
8637
+ {
8638
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
8639
+ onClick: () => setEditorState(
8640
+ (current) => current ? { ...current, steps: [...current.steps, blankStep()] } : current
8641
+ ),
8642
+ type: "button",
8643
+ children: "Add step"
8644
+ }
8645
+ )
8646
+ ] }),
8647
+ editorState.steps.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-empty-state", children: [
8648
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "No steps configured" }),
8649
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "Add a first step to start building the public form flow." })
8650
+ ] }) : null,
8651
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-step-editor-list", children: editorState.steps.map((step, stepIndex) => {
8652
+ const fields = getFields(step);
8653
+ const requiredCount = fields.filter((field) => field.required === true).length;
8654
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("details", { className: "orion-admin-step-editor", open: true, children: [
8655
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("summary", { className: "orion-admin-step-editor-summary", children: [
8656
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-workflow-node-number", children: stepIndex + 1 }),
8657
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-step-editor-title", children: getStepTitle(step, stepIndex) }),
8658
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "orion-admin-step-editor-meta", children: [
8659
+ fields.length,
8660
+ " field",
8661
+ fields.length === 1 ? "" : "s",
8662
+ requiredCount > 0 ? ` \xB7 ${requiredCount} required` : ""
8663
+ ] }),
8664
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-workflow-node-destination", children: getStepDestination(stepIndex, editorState.steps.length) })
8665
+ ] }),
8666
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-step-editor-body", children: [
8667
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-step-editor-actions", children: [
8668
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8669
+ "button",
8670
+ {
8671
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
8672
+ disabled: stepIndex === 0,
8673
+ onClick: () => moveStep(stepIndex, -1),
8674
+ type: "button",
8675
+ children: "Move up"
8676
+ }
8677
+ ),
8678
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8679
+ "button",
8680
+ {
8681
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
8682
+ disabled: stepIndex === editorState.steps.length - 1,
8683
+ onClick: () => moveStep(stepIndex, 1),
8684
+ type: "button",
8685
+ children: "Move down"
8686
+ }
8687
+ ),
8688
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8689
+ "button",
8690
+ {
8691
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
8692
+ onClick: () => setEditorState(
8693
+ (current) => current ? {
8694
+ ...current,
8695
+ steps: current.steps.filter((_, index) => index !== stepIndex)
8696
+ } : current
8697
+ ),
8698
+ type: "button",
8699
+ children: "Remove step"
8700
+ }
8701
+ )
8702
+ ] }),
8703
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-step-settings-grid", children: [
8704
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8705
+ "Step title",
8706
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8707
+ "input",
8708
+ {
8709
+ onChange: (event) => updateStep(stepIndex, { title: event.target.value }),
8710
+ type: "text",
8711
+ value: getNonEmptyText(step.title)
8712
+ }
8713
+ )
8714
+ ] }),
8715
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8716
+ "Next button label",
8717
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8718
+ "input",
8719
+ {
8720
+ onChange: (event) => updateStep(stepIndex, { nextLabel: event.target.value }),
8721
+ placeholder: "Next",
8722
+ type: "text",
8723
+ value: getNonEmptyText(step.nextLabel)
8724
+ }
8725
+ )
8726
+ ] })
8727
+ ] }),
8728
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8729
+ "Step intro text",
8730
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8731
+ "textarea",
8732
+ {
8733
+ onChange: (event) => updateStep(stepIndex, { subtitle: event.target.value }),
8734
+ rows: 3,
8735
+ value: getNonEmptyText(step.subtitle)
8736
+ }
8737
+ )
8738
+ ] }),
8739
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { style: checkboxLabelStyle, children: [
8740
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8741
+ "input",
8742
+ {
8743
+ checked: step.allowSkip === true,
8744
+ onChange: (event) => updateStep(stepIndex, { allowSkip: event.target.checked }),
8745
+ type: "checkbox"
8746
+ }
8747
+ ),
8748
+ "Allow visitors to skip this step"
8749
+ ] }),
8750
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-field-list-header", children: [
8751
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { children: [
8752
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "Fields in this step" }),
8753
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "These appear together before the visitor moves to the next step." })
8754
+ ] }),
8755
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8756
+ "button",
8757
+ {
8758
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
8759
+ onClick: () => setEditorState(
8760
+ (current) => current ? {
8761
+ ...current,
8762
+ steps: current.steps.map(
8763
+ (currentStep, index) => index === stepIndex ? { ...currentStep, fields: [...getFields(currentStep), blankField()] } : currentStep
8764
+ )
8765
+ } : current
8766
+ ),
8767
+ type: "button",
8768
+ children: "Add field"
8769
+ }
8770
+ )
8771
+ ] }),
8772
+ fields.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-field-editor-list", children: fields.map((field, fieldIndex) => {
8773
+ const label = getFieldLabel(field, fieldIndex);
8774
+ const fieldType = getNonEmptyText(field.type, "text");
8775
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("details", { className: "orion-admin-field-editor", children: [
8776
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("summary", { className: "orion-admin-field-editor-summary", children: [
8777
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-field-order", children: fieldIndex + 1 }),
8778
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-field-editor-title", children: label }),
8779
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "orion-admin-field-editor-meta", children: [
8780
+ formatFieldTypeLabel(fieldType),
8781
+ field.required === true ? " \xB7 Required" : ""
8782
+ ] })
8783
+ ] }),
8784
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-field-editor-body", children: [
8785
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-step-editor-actions", children: [
8786
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8787
+ "button",
8788
+ {
8789
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
8790
+ disabled: fieldIndex === 0,
8791
+ onClick: () => moveField(stepIndex, fieldIndex, -1),
8792
+ type: "button",
8793
+ children: "Move up"
8794
+ }
8795
+ ),
8796
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8797
+ "button",
8798
+ {
8799
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
8800
+ disabled: fieldIndex === fields.length - 1,
8801
+ onClick: () => moveField(stepIndex, fieldIndex, 1),
8802
+ type: "button",
8803
+ children: "Move down"
8804
+ }
8805
+ ),
8806
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8807
+ "button",
8808
+ {
8809
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
8810
+ onClick: () => setEditorState((current) => {
8811
+ if (!current) return current;
8812
+ return {
8813
+ ...current,
8814
+ steps: current.steps.map(
8815
+ (currentStep, index) => index === stepIndex ? {
8816
+ ...currentStep,
8817
+ fields: getFields(currentStep).filter(
8818
+ (_, currentFieldIndex) => currentFieldIndex !== fieldIndex
8819
+ )
8820
+ } : currentStep
8821
+ )
8822
+ };
8823
+ }),
8824
+ type: "button",
8825
+ children: "Remove field"
8826
+ }
8827
+ )
8828
+ ] }),
8829
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-step-settings-grid", children: [
8830
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8831
+ "Field label",
8832
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8833
+ "input",
8834
+ {
8835
+ onChange: (event) => {
8836
+ const nextLabel = event.target.value;
8837
+ const currentName = getNonEmptyText(field.name);
8838
+ updateField(stepIndex, fieldIndex, {
8839
+ label: nextLabel,
8840
+ name: currentName || slugifyFieldName(nextLabel)
8841
+ });
8842
+ },
8843
+ type: "text",
8844
+ value: label
8845
+ }
8846
+ )
8847
+ ] }),
8848
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8849
+ "Field type",
8850
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8851
+ "select",
8852
+ {
8853
+ onChange: (event) => updateField(stepIndex, fieldIndex, { type: event.target.value }),
8854
+ value: fieldType,
8855
+ children: fieldTypeOptions.map((option) => /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: option, children: formatFieldTypeLabel(option) }, option))
8856
+ }
8857
+ )
8858
+ ] })
8859
+ ] }),
8860
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8861
+ "Field key",
8862
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8863
+ "input",
8864
+ {
8865
+ onChange: (event) => updateField(stepIndex, fieldIndex, { name: event.target.value }),
8866
+ type: "text",
8867
+ value: getNonEmptyText(field.name)
8868
+ }
8869
+ )
8870
+ ] }),
8871
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { style: checkboxLabelStyle, children: [
8872
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8873
+ "input",
8874
+ {
8875
+ checked: field.required === true,
8876
+ onChange: (event) => updateField(stepIndex, fieldIndex, { required: event.target.checked }),
8877
+ type: "checkbox"
8878
+ }
8879
+ ),
8880
+ "Required"
8881
+ ] }),
8882
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8883
+ "Help text",
8884
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8885
+ "textarea",
8886
+ {
8887
+ onChange: (event) => updateField(stepIndex, fieldIndex, { helpText: event.target.value }),
8888
+ rows: 2,
8889
+ value: getNonEmptyText(field.helpText)
8890
+ }
8891
+ )
8892
+ ] }),
8893
+ ["select", "radio", "checkbox-group"].includes(fieldType) ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8894
+ "Options",
8895
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8896
+ "textarea",
8897
+ {
8898
+ onChange: (event) => updateField(stepIndex, fieldIndex, {
8899
+ options: fromOptionsText(event.target.value)
8900
+ }),
8901
+ placeholder: "Option one\nOption two",
8902
+ rows: 4,
8903
+ value: toOptionsText(field.options)
8904
+ }
8905
+ )
8906
+ ] }) : null
8907
+ ] })
8908
+ ] }, `edit-field-${stepIndex}-${fieldIndex}`);
8909
+ }) }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-empty-state", children: [
8910
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "No fields in this step" }),
8911
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "Add a field so visitors have something to answer here." })
8912
+ ] })
8913
+ ] })
8914
+ ] }, `edit-step-${stepIndex}`);
8915
+ }) })
8916
+ ] }),
8917
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("button", { disabled: saving, type: "submit", children: saving ? "Saving..." : "Save Form" })
8918
+ ] })
8919
+ ] })
8920
+ ] }) : null
8921
+ ]
8922
+ }
8923
+ ) });
8924
+ }
8925
+
8926
+ // src/admin/components/studio/AdminStudioFormSubmissionView.tsx
8927
+ var import_link5 = __toESM(require("next/link"));
8928
+ var import_react33 = require("react");
8929
+ var import_jsx_runtime42 = require("react/jsx-runtime");
8930
+ var sectionGridStyle2 = {
8931
+ display: "grid",
8932
+ gap: "1rem",
8933
+ gridTemplateColumns: "repeat(auto-fit, minmax(320px, 1fr))"
8934
+ };
8935
+ var nestedListStyle = {
8936
+ display: "grid",
8937
+ gap: "0.45rem",
8938
+ margin: 0,
8939
+ padding: 0
8940
+ };
8941
+ var renderFieldValue = (value) => {
8942
+ if (value === null || value === void 0) {
8943
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-list-meta", children: "No value" });
8944
+ }
8945
+ if (typeof value === "boolean") {
8946
+ return value ? "Yes" : "No";
8947
+ }
8948
+ if (typeof value === "number") {
8949
+ return String(value);
8950
+ }
8951
+ if (typeof value === "string") {
8952
+ return value.trim().length > 0 ? value : /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-list-meta", children: "No value" });
8953
+ }
8954
+ if (Array.isArray(value)) {
8955
+ const entries = value.filter((entry) => entry !== null && entry !== void 0 && entry !== "");
8956
+ if (entries.length === 0) {
8957
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-list-meta", children: "No value" });
8958
+ }
8959
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("ul", { style: nestedListStyle, children: entries.map((entry, index) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("li", { children: renderFieldValue(entry) }, index)) });
8960
+ }
8961
+ if (typeof value === "object") {
8962
+ const entries = Object.entries(value).filter(
8963
+ ([, entryValue]) => entryValue !== null && entryValue !== void 0 && entryValue !== ""
8964
+ );
8965
+ if (entries.length === 0) {
8966
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-list-meta", children: "No value" });
8967
+ }
8968
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { style: { display: "grid", gap: "0.65rem" }, children: entries.map(([key, entryValue]) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-meta-row", children: [
8969
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-label", children: humanizeKey2(key) }),
8970
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-value", children: renderFieldValue(entryValue) })
8971
+ ] }, key)) });
8972
+ }
8973
+ return String(value);
8974
+ };
8975
+ function getSubmissionIDFromPathname(pathname) {
8976
+ return getIDFromPathname(pathname, "/forms/submissions/");
8977
+ }
8978
+ function AdminStudioFormSubmissionView(props) {
8979
+ const formsCollectionSlug = getPropString14(props, "formsCollectionSlug", "forms");
8980
+ const formSubmissionsCollectionSlug = getPropString14(
8981
+ props,
8982
+ "formSubmissionsCollectionSlug",
8983
+ "form-submissions"
8984
+ );
8985
+ const adminBasePath = useAdminBasePath();
8986
+ const formsPath = resolveAdminPath(adminBasePath, "/forms");
8987
+ const submissionIDFromParams = (0, import_react33.useMemo)(() => getParam3(props.params, "id"), [props.params]);
8988
+ const [submissionID, setSubmissionID] = (0, import_react33.useState)(submissionIDFromParams);
8989
+ const [didResolvePathFallback, setDidResolvePathFallback] = (0, import_react33.useState)(false);
8990
+ const [doc, setDoc] = (0, import_react33.useState)(null);
8991
+ const [formDoc, setFormDoc] = (0, import_react33.useState)(null);
8992
+ const [loading, setLoading] = (0, import_react33.useState)(true);
8993
+ const [error, setError] = (0, import_react33.useState)(null);
8994
+ const [confirmDelete, setConfirmDelete] = (0, import_react33.useState)(false);
8995
+ const [deleting, setDeleting] = (0, import_react33.useState)(false);
8996
+ (0, import_react33.useEffect)(() => {
8997
+ if (submissionIDFromParams) {
8998
+ setSubmissionID(submissionIDFromParams);
8999
+ setDidResolvePathFallback(true);
9000
+ return;
9001
+ }
9002
+ if (typeof window !== "undefined") {
9003
+ setSubmissionID(getSubmissionIDFromPathname(window.location.pathname));
9004
+ }
9005
+ setDidResolvePathFallback(true);
9006
+ }, [submissionIDFromParams]);
9007
+ const loadDoc = async (id) => {
9008
+ setLoading(true);
9009
+ setError(null);
9010
+ try {
9011
+ const response = await fetch(
9012
+ `/api/${formSubmissionsCollectionSlug}/${encodeURIComponent(id)}?depth=2&draft=true`,
9013
+ {
9014
+ credentials: "include"
9015
+ }
9016
+ );
9017
+ if (!response.ok) {
9018
+ throw new Error(`Failed to load submission (${response.status}).`);
9019
+ }
9020
+ const nextDoc = await response.json();
9021
+ const relatedForm = nextDoc.form && typeof nextDoc.form === "object" && !Array.isArray(nextDoc.form) ? nextDoc.form : null;
9022
+ let nextFormDoc = relatedForm;
9023
+ const relatedFormID2 = getFormID3(nextDoc.form);
9024
+ if (!nextFormDoc && relatedFormID2) {
9025
+ const formResponse = await fetch(
9026
+ `/api/${formsCollectionSlug}/${encodeURIComponent(relatedFormID2)}?depth=0&draft=true`,
9027
+ {
9028
+ credentials: "include"
9029
+ }
9030
+ );
9031
+ if (formResponse.ok) {
9032
+ nextFormDoc = await formResponse.json();
9033
+ }
9034
+ }
9035
+ setDoc(nextDoc);
9036
+ setFormDoc(nextFormDoc);
9037
+ } catch (loadError) {
9038
+ setError(loadError instanceof Error ? loadError.message : "Failed to load submission.");
9039
+ setDoc(null);
9040
+ setFormDoc(null);
9041
+ } finally {
9042
+ setLoading(false);
9043
+ }
9044
+ };
9045
+ (0, import_react33.useEffect)(() => {
9046
+ if (!submissionID) {
9047
+ return;
9048
+ }
9049
+ void loadDoc(submissionID);
9050
+ }, [formsCollectionSlug, formSubmissionsCollectionSlug, submissionID]);
9051
+ const deleteSubmission = async () => {
9052
+ if (!submissionID) {
9053
+ return;
9054
+ }
9055
+ setDeleting(true);
9056
+ setError(null);
9057
+ try {
9058
+ const response = await fetch(`/api/${formSubmissionsCollectionSlug}/${encodeURIComponent(submissionID)}`, {
9059
+ credentials: "include",
9060
+ method: "DELETE"
9061
+ });
9062
+ if (!response.ok) {
9063
+ throw new Error(`Failed to delete submission (${response.status}).`);
9064
+ }
9065
+ const relatedFormID2 = doc ? getFormID3(doc.form) : "";
9066
+ const targetHref = relatedFormID2 ? resolveAdminPath(adminBasePath, `/forms/${relatedFormID2}`) : formsPath;
9067
+ window.location.assign(targetHref);
9068
+ } catch (deleteError) {
9069
+ setError(deleteError instanceof Error ? deleteError.message : "Failed to delete submission.");
9070
+ setDeleting(false);
9071
+ }
9072
+ };
9073
+ if (!submissionID && !didResolvePathFallback) {
9074
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
9075
+ AdminPage,
9076
+ {
9077
+ breadcrumbs: [
9078
+ { label: "Dashboard", href: adminBasePath },
9079
+ { label: "Forms", href: formsPath },
9080
+ { label: "Submission" }
9081
+ ],
9082
+ description: "Loading submission workspace...",
9083
+ title: "Submission",
9084
+ children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_jsx_runtime42.Fragment, {})
9085
+ }
9086
+ ) });
9087
+ }
9088
+ const relatedFormID = doc ? getFormID3(doc.form) : "";
9089
+ const formPath = relatedFormID ? resolveAdminPath(adminBasePath, `/forms/${relatedFormID}`) : formsPath;
9090
+ const formTitle = formDoc ? getFormTitle2(formDoc) : getFormTitle2(doc?.formSlug);
9091
+ const uploads = doc ? getUploads2(doc.files) : [];
9092
+ const identity = doc ? getNameAndEmail2(doc.data) : {};
9093
+ const fieldLabels = formDoc ? buildFieldLabelMap2(formDoc) : /* @__PURE__ */ new Map();
9094
+ const previewFields = doc ? getPreviewFields2(doc.data, fieldLabels) : [];
9095
+ const answerEntries = doc && doc.data && typeof doc.data === "object" ? Object.entries(doc.data) : [];
9096
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
9097
+ AdminPage,
9098
+ {
9099
+ breadcrumbs: [
9100
+ { label: "Dashboard", href: adminBasePath },
9101
+ { label: "Forms", href: formsPath },
9102
+ ...relatedFormID ? [{ label: formTitle, href: formPath }] : [{ label: formTitle }],
9103
+ { label: "Submission" }
9104
+ ],
9105
+ description: "Review the submitted answers, related files, and linked form details.",
9106
+ title: "Submission",
9107
+ children: [
9108
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "orion-admin-list-meta", children: "Loading..." }) : null,
9109
+ error ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "orion-admin-error", children: error }) : null,
9110
+ !loading && !error && doc && submissionID ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { style: { display: "grid", gap: "1rem" }, children: [
9111
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-forms-summary-grid", children: [
9112
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("article", { className: "orion-admin-overview-stat", children: [
9113
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-overview-stat-label", children: "Submitted" }),
9114
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: formatDate2(doc.submittedAt) }),
9115
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { children: "Captured timestamp for this response." })
9116
+ ] }),
9117
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("article", { className: "orion-admin-overview-stat", children: [
9118
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-overview-stat-label", children: "Uploads" }),
9119
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: uploads.length }),
9120
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { children: "Files attached by the submitter." })
9121
+ ] }),
9122
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("article", { className: "orion-admin-overview-stat", children: [
9123
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-overview-stat-label", children: "Highlighted answers" }),
9124
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: previewFields.length }),
9125
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { children: "Readable answer previews from this response." })
9126
+ ] })
9127
+ ] }),
9128
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { style: sectionGridStyle2, children: [
9129
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { style: { display: "grid", gap: "1rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-card", children: [
9130
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: "Response details" }),
9131
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { children: "Formatted answers using the current form field labels when available." }),
9132
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { style: { display: "grid", gap: "0.85rem", marginTop: "1rem" }, children: answerEntries.length > 0 ? answerEntries.map(([key, value]) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-form", children: [
9133
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { children: [
9134
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: fieldLabels.get(key) || humanizeKey2(key) }),
9135
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "orion-admin-list-meta", children: key })
9136
+ ] }),
9137
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { children: renderFieldValue(value) })
9138
+ ] }, key)) : /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-empty-state", children: [
9139
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: "No answers available" }),
9140
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { children: "This submission does not contain visible response details." })
9141
+ ] }) })
9142
+ ] }) }),
9143
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { style: { display: "grid", gap: "1rem" }, children: [
9144
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-card orion-admin-meta-table", children: [
9145
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-meta-row", children: [
9146
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-label", children: "Form" }),
9147
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-value", children: relatedFormID ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_link5.default, { href: formPath, children: formTitle }) : formTitle })
9148
+ ] }),
9149
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-meta-row", children: [
9150
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-label", children: "Primary contact" }),
9151
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-value", children: identity.name || identity.email || "Unknown" })
9152
+ ] }),
9153
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-meta-row", children: [
9154
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-label", children: "Email" }),
9155
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-value", children: identity.email || "Not provided" })
9156
+ ] }),
9157
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-meta-row", children: [
9158
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-label", children: "Submission ID" }),
9159
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-value", children: submissionID })
9160
+ ] }),
9161
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-meta-row", children: [
9162
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-label", children: "Form slug" }),
9163
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-value", children: typeof doc.formSlug === "string" && doc.formSlug.trim().length > 0 ? doc.formSlug : "Unavailable" })
9164
+ ] })
9165
+ ] }),
9166
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-card", children: [
9167
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: "Attached uploads" }),
9168
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { children: "Files linked to this response remain inside the Studio workspace." }),
9169
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { style: { display: "grid", gap: "0.75rem", marginTop: "1rem" }, children: uploads.length > 0 ? uploads.map((upload) => {
9170
+ const uploadID = typeof upload.id === "string" || typeof upload.id === "number" ? String(upload.id) : "";
9171
+ if (!uploadID) return null;
9172
+ const uploadPath = resolveAdminPath(adminBasePath, `/forms/uploads/${uploadID}`);
9173
+ const meta = [formatFileSize4(upload.filesize), typeof upload.mimeType === "string" ? upload.mimeType : null].filter(Boolean).join(" \xB7 ");
9174
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_link5.default, { className: "orion-admin-list-item", href: uploadPath, children: [
9175
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { children: [
9176
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: typeof upload.filename === "string" && upload.filename.trim().length > 0 ? upload.filename : `Upload ${uploadID}` }),
9177
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "orion-admin-list-meta", children: meta || "Open file details" })
9178
+ ] }),
9179
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-action-button orion-admin-action-button--ghost", children: "Open" })
9180
+ ] }, uploadID);
9181
+ }) : /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-empty-state", children: [
9182
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: "No files attached" }),
9183
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { children: "This response did not include any uploads." })
9184
+ ] }) })
9185
+ ] }),
9186
+ confirmDelete ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-form", style: { borderColor: "#b42318" }, children: [
9187
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { style: { fontWeight: 700, margin: 0 }, children: "Delete this submission?" }),
9188
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "orion-admin-list-meta", style: { margin: 0 }, children: "This action cannot be undone and will remove the stored response." }),
9189
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-inline-actions", children: [
9190
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("button", { disabled: deleting, onClick: deleteSubmission, type: "button", children: deleting ? "Deleting..." : "Yes, Delete" }),
9191
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("button", { onClick: () => setConfirmDelete(false), type: "button", children: "Cancel" })
9192
+ ] })
9193
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
9194
+ "button",
9195
+ {
9196
+ className: "orion-admin-action-button",
9197
+ onClick: () => setConfirmDelete(true),
9198
+ style: { background: "#b42318" },
9199
+ type: "button",
9200
+ children: "Delete Submission"
9201
+ }
9202
+ )
9203
+ ] })
9204
+ ] })
9205
+ ] }) : null
9206
+ ]
9207
+ }
9208
+ ) });
9209
+ }
9210
+
9211
+ // src/admin/components/studio/AdminStudioFormUploadView.tsx
9212
+ var import_react34 = require("react");
9213
+ var import_jsx_runtime43 = require("react/jsx-runtime");
9214
+ var previewStyle = {
9215
+ borderRadius: 14,
9216
+ display: "block",
9217
+ maxHeight: "28rem",
9218
+ objectFit: "contain",
9219
+ width: "100%"
9220
+ };
9221
+ function getUploadIDFromPathname(pathname) {
9222
+ return getIDFromPathname(pathname, "/forms/uploads/");
9223
+ }
9224
+ function AdminStudioFormUploadView(props) {
9225
+ const formUploadsCollectionSlug = getPropString14(props, "formUploadsCollectionSlug", "form-uploads");
9226
+ const adminBasePath = useAdminBasePath();
9227
+ const formsPath = resolveAdminPath(adminBasePath, "/forms");
9228
+ const uploadIDFromParams = (0, import_react34.useMemo)(() => getParam3(props.params, "id"), [props.params]);
9229
+ const [uploadID, setUploadID] = (0, import_react34.useState)(uploadIDFromParams);
9230
+ const [didResolvePathFallback, setDidResolvePathFallback] = (0, import_react34.useState)(false);
9231
+ const [doc, setDoc] = (0, import_react34.useState)(null);
9232
+ const [loading, setLoading] = (0, import_react34.useState)(true);
9233
+ const [error, setError] = (0, import_react34.useState)(null);
9234
+ const [savedMessage, setSavedMessage] = (0, import_react34.useState)(null);
9235
+ const [saving, setSaving] = (0, import_react34.useState)(false);
9236
+ const [confirmDelete, setConfirmDelete] = (0, import_react34.useState)(false);
9237
+ const [deleting, setDeleting] = (0, import_react34.useState)(false);
9238
+ (0, import_react34.useEffect)(() => {
9239
+ if (uploadIDFromParams) {
9240
+ setUploadID(uploadIDFromParams);
9241
+ setDidResolvePathFallback(true);
9242
+ return;
9243
+ }
9244
+ if (typeof window !== "undefined") {
9245
+ setUploadID(getUploadIDFromPathname(window.location.pathname));
9246
+ }
9247
+ setDidResolvePathFallback(true);
9248
+ }, [uploadIDFromParams]);
9249
+ const loadDoc = async (id) => {
9250
+ setLoading(true);
9251
+ setError(null);
9252
+ try {
9253
+ const response = await fetch(`/api/${formUploadsCollectionSlug}/${encodeURIComponent(id)}?depth=0&draft=true`, {
9254
+ credentials: "include"
9255
+ });
9256
+ if (!response.ok) {
9257
+ throw new Error(`Failed to load upload (${response.status}).`);
9258
+ }
9259
+ const nextDoc = await response.json();
9260
+ setDoc(nextDoc);
9261
+ } catch (loadError) {
9262
+ setError(loadError instanceof Error ? loadError.message : "Failed to load upload.");
9263
+ setDoc(null);
9264
+ } finally {
9265
+ setLoading(false);
9266
+ }
9267
+ };
9268
+ (0, import_react34.useEffect)(() => {
9269
+ if (!uploadID) {
9270
+ return;
9271
+ }
9272
+ void loadDoc(uploadID);
9273
+ }, [formUploadsCollectionSlug, uploadID]);
9274
+ const save = async (event) => {
9275
+ event.preventDefault();
9276
+ if (!uploadID) {
9277
+ return;
9278
+ }
9279
+ setSaving(true);
9280
+ setError(null);
9281
+ setSavedMessage(null);
9282
+ try {
9283
+ const formData = new FormData(event.currentTarget);
9284
+ const alt = String(formData.get("alt") || "").trim();
9285
+ const response = await fetch(`/api/${formUploadsCollectionSlug}/${encodeURIComponent(uploadID)}`, {
9286
+ body: JSON.stringify({ alt }),
9287
+ credentials: "include",
9288
+ headers: {
9289
+ "Content-Type": "application/json"
9290
+ },
9291
+ method: "PATCH"
9292
+ });
9293
+ if (!response.ok) {
9294
+ throw new Error(`Failed to save upload (${response.status}).`);
9295
+ }
9296
+ const nextDoc = await response.json();
9297
+ setDoc(nextDoc);
9298
+ setSavedMessage("Saved.");
9299
+ } catch (saveError) {
9300
+ setError(saveError instanceof Error ? saveError.message : "Failed to save upload.");
9301
+ } finally {
9302
+ setSaving(false);
9303
+ }
9304
+ };
9305
+ const deleteUpload = async () => {
9306
+ if (!uploadID) {
9307
+ return;
9308
+ }
9309
+ setDeleting(true);
9310
+ setError(null);
9311
+ try {
9312
+ const response = await fetch(`/api/${formUploadsCollectionSlug}/${encodeURIComponent(uploadID)}`, {
9313
+ credentials: "include",
9314
+ method: "DELETE"
9315
+ });
9316
+ if (!response.ok) {
9317
+ throw new Error(`Failed to delete upload (${response.status}).`);
9318
+ }
9319
+ window.location.assign(formsPath);
9320
+ } catch (deleteError) {
9321
+ setError(deleteError instanceof Error ? deleteError.message : "Failed to delete upload.");
9322
+ setDeleting(false);
9323
+ }
9324
+ };
9325
+ if (!uploadID && !didResolvePathFallback) {
9326
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
9327
+ AdminPage,
9328
+ {
9329
+ breadcrumbs: [
9330
+ { label: "Dashboard", href: adminBasePath },
9331
+ { label: "Forms", href: formsPath },
9332
+ { label: "Upload" }
9333
+ ],
9334
+ description: "Loading upload workspace...",
9335
+ title: "Upload",
9336
+ children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_jsx_runtime43.Fragment, {})
9337
+ }
9338
+ ) });
9339
+ }
9340
+ const filename = doc && typeof doc.filename === "string" && doc.filename.trim().length > 0 ? doc.filename : uploadID ? `Upload ${uploadID}` : "Upload";
9341
+ const mimeType = doc && typeof doc.mimeType === "string" ? doc.mimeType : "";
9342
+ const sourceURL = doc && typeof doc.url === "string" && doc.url.trim().length > 0 ? doc.url : null;
9343
+ const canPreview = Boolean(sourceURL && mimeType.startsWith("image/"));
9344
+ const createdAt = doc?.createdAt ?? doc?.updatedAt;
9345
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
9346
+ AdminPage,
9347
+ {
9348
+ breadcrumbs: [
9349
+ { label: "Dashboard", href: adminBasePath },
9350
+ { label: "Forms", href: formsPath },
9351
+ { label: filename }
9352
+ ],
9353
+ description: "Review file metadata, update alt text, and remove private uploads from Studio.",
9354
+ title: "Upload",
9355
+ children: [
9356
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "orion-admin-list-meta", children: "Loading..." }) : null,
9357
+ error ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "orion-admin-error", children: error }) : null,
9358
+ savedMessage ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "orion-admin-success", children: savedMessage }) : null,
9359
+ !loading && !error && doc && uploadID ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "orion-admin-grid", style: { alignItems: "start" }, children: [
9360
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { style: { display: "grid", gap: "0.8rem" }, children: [
9361
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "orion-admin-card", children: canPreview && sourceURL ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("img", { alt: filename, src: sourceURL, style: previewStyle }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, { children: [
9362
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("strong", { children: "No inline preview" }),
9363
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { children: mimeType ? `Preview unavailable for ${mimeType}.` : "Preview unavailable for this file." })
9364
+ ] }) }),
9365
+ sourceURL ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("a", { className: "orion-admin-action-button", href: sourceURL, rel: "noreferrer", target: "_blank", children: "Open File" }) : null
9366
+ ] }),
9367
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { style: { display: "grid", gap: "0.8rem" }, children: [
9368
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "orion-admin-card orion-admin-meta-table", children: [
9369
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "orion-admin-meta-row", children: [
9370
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "orion-admin-meta-label", children: "Filename" }),
9371
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "orion-admin-meta-value", children: filename })
9372
+ ] }),
9373
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "orion-admin-meta-row", children: [
9374
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "orion-admin-meta-label", children: "File size" }),
9375
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "orion-admin-meta-value", children: formatFileSize4(doc.filesize) || "Unavailable" })
9376
+ ] }),
9377
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "orion-admin-meta-row", children: [
9378
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "orion-admin-meta-label", children: "Type" }),
9379
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "orion-admin-meta-value", children: mimeType || "Unavailable" })
9380
+ ] }),
9381
+ typeof doc.width === "number" && typeof doc.height === "number" ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "orion-admin-meta-row", children: [
9382
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "orion-admin-meta-label", children: "Dimensions" }),
9383
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "orion-admin-meta-value", children: [
9384
+ doc.width,
9385
+ " x ",
9386
+ doc.height,
9387
+ "px"
9388
+ ] })
9389
+ ] }) : null,
9390
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "orion-admin-meta-row", children: [
9391
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "orion-admin-meta-label", children: "Uploaded" }),
9392
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "orion-admin-meta-value", children: formatDate2(createdAt) })
9393
+ ] })
9394
+ ] }),
9395
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("form", { className: "orion-admin-form", onSubmit: save, children: [
9396
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("strong", { children: "Asset details" }),
9397
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("label", { children: [
9398
+ "Alt text",
9399
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("input", { defaultValue: typeof doc.alt === "string" ? doc.alt : "", name: "alt", type: "text" })
9400
+ ] }),
9401
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", { disabled: saving, type: "submit", children: saving ? "Saving..." : "Save Upload" })
9402
+ ] }),
9403
+ confirmDelete ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "orion-admin-form", style: { borderColor: "#b42318" }, children: [
9404
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { style: { fontWeight: 700, margin: 0 }, children: "Delete this upload?" }),
9405
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "orion-admin-list-meta", style: { margin: 0 }, children: "This removes the stored file and any linked submission attachment references." }),
9406
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "orion-admin-inline-actions", children: [
9407
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", { disabled: deleting, onClick: deleteUpload, type: "button", children: deleting ? "Deleting..." : "Yes, Delete" }),
9408
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", { onClick: () => setConfirmDelete(false), type: "button", children: "Cancel" })
9409
+ ] })
9410
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
9411
+ "button",
9412
+ {
9413
+ className: "orion-admin-action-button",
9414
+ onClick: () => setConfirmDelete(true),
9415
+ style: { background: "#b42318" },
9416
+ type: "button",
9417
+ children: "Delete Upload"
9418
+ }
9419
+ )
9420
+ ] })
9421
+ ] }) : null
9422
+ ]
9423
+ }
9424
+ ) });
9425
+ }
9426
+
9427
+ // src/admin/components/studio/AdminStudioToolsView.tsx
9428
+ var import_react35 = require("react");
9429
+ var import_ui12 = require("@payloadcms/ui");
9430
+ var import_jsx_runtime44 = require("react/jsx-runtime");
9431
+ var userRoles = ["admin", "developer", "editor", "client"];
9432
+ var hasAdminAccess3 = (user) => {
9433
+ if (!user || typeof user !== "object") return false;
9434
+ const role = user.role;
9435
+ return typeof role === "string" && (role === "admin" || role === "developer");
9436
+ };
9437
+ var normalizeRole = (value) => userRoles.includes(value) ? value : "editor";
9438
+ function AdminStudioToolsView(props) {
9439
+ const { user } = (0, import_ui12.useAuth)();
9440
+ const adminBasePath = useAdminBasePath();
9441
+ const [docs, setDocs] = (0, import_react35.useState)([]);
9442
+ const [loading, setLoading] = (0, import_react35.useState)(true);
9443
+ const [error, setError] = (0, import_react35.useState)(null);
9444
+ const [savedMessage, setSavedMessage] = (0, import_react35.useState)(null);
9445
+ const [createSubmitting, setCreateSubmitting] = (0, import_react35.useState)(false);
9446
+ const [updatingUserID, setUpdatingUserID] = (0, import_react35.useState)(null);
9447
+ if (!hasAdminAccess3(user)) {
9448
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
9449
+ AdminPage,
9450
+ {
9451
+ breadcrumbs: [
9452
+ { label: "Dashboard", href: adminBasePath },
9453
+ { label: "Admin Tools" }
9454
+ ],
9455
+ description: "You do not have access to this section.",
9456
+ title: "Admin Tools",
9457
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "orion-admin-card", children: [
9458
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("strong", { children: "Access denied" }),
9459
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { children: "This section is restricted to administrator and developer accounts." })
9460
+ ] })
9461
+ }
9462
+ ) });
9463
+ }
9464
+ const loadUsers = async () => {
9465
+ setLoading(true);
9466
+ setError(null);
9467
+ try {
9468
+ const params = new URLSearchParams({
9469
+ depth: "0",
9470
+ draft: "true",
9471
+ limit: "200",
9472
+ sort: "email"
9473
+ });
9474
+ const response = await fetch(`/api/users?${params.toString()}`, {
9475
+ credentials: "include"
9476
+ });
9477
+ if (!response.ok) {
9478
+ throw new Error(`Failed to load users (${response.status}).`);
9479
+ }
9480
+ const payload = await response.json();
9481
+ setDocs(Array.isArray(payload.docs) ? payload.docs : []);
9482
+ } catch (loadError) {
9483
+ setError(loadError instanceof Error ? loadError.message : "Failed to load users.");
9484
+ } finally {
9485
+ setLoading(false);
9486
+ }
9487
+ };
9488
+ (0, import_react35.useEffect)(() => {
9489
+ void loadUsers();
9490
+ }, []);
9491
+ const createUser = async (event) => {
9492
+ event.preventDefault();
9493
+ const form = event.currentTarget;
9494
+ setCreateSubmitting(true);
9495
+ setError(null);
9496
+ setSavedMessage(null);
9497
+ try {
9498
+ const formData = new FormData(form);
9499
+ const email = String(formData.get("email") || "").trim();
9500
+ const password = String(formData.get("password") || "");
9501
+ const fullName = String(formData.get("fullName") || "").trim();
9502
+ const role = normalizeRole(String(formData.get("role") || "editor").trim());
9503
+ if (!email || !password) {
9504
+ throw new Error("Email and password are required.");
9505
+ }
9506
+ const response = await fetch("/api/users", {
9507
+ body: JSON.stringify({
9508
+ email,
9509
+ fullName,
9510
+ password,
9511
+ role
9512
+ }),
9513
+ credentials: "include",
9514
+ headers: {
9515
+ "Content-Type": "application/json"
9516
+ },
9517
+ method: "POST"
9518
+ });
8094
9519
  if (!response.ok) {
8095
9520
  throw new Error(`Failed to create user (${response.status}).`);
8096
9521
  }
8097
- event.currentTarget.reset();
9522
+ form.reset();
8098
9523
  await loadUsers();
8099
9524
  setSavedMessage("User created.");
8100
9525
  } catch (createError) {
@@ -8132,7 +9557,7 @@ function AdminStudioToolsView(props) {
8132
9557
  setUpdatingUserID(null);
8133
9558
  }
8134
9559
  };
8135
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
9560
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
8136
9561
  AdminPage,
8137
9562
  {
8138
9563
  breadcrumbs: [
@@ -8142,53 +9567,44 @@ function AdminStudioToolsView(props) {
8142
9567
  description: "Manage users and fallback links to Payload native admin.",
8143
9568
  title: "Admin Tools",
8144
9569
  children: [
8145
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-inline-actions", style: { marginBottom: "1rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("a", { className: "orion-admin-action-button", href: "/admin-core", target: "_blank", children: "Open Payload Core Admin" }) }),
8146
- error ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-error", style: { marginBottom: "1rem" }, children: error }) : null,
8147
- savedMessage ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-success", style: { marginBottom: "1rem" }, children: savedMessage }) : null,
8148
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("form", { className: "orion-admin-form", onSubmit: createUser, style: { marginBottom: "1rem" }, children: [
8149
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "Create User" }),
8150
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
9570
+ error ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "orion-admin-error", style: { marginBottom: "1rem" }, children: error }) : null,
9571
+ savedMessage ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "orion-admin-success", style: { marginBottom: "1rem" }, children: savedMessage }) : null,
9572
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("form", { className: "orion-admin-form", onSubmit: createUser, style: { marginBottom: "1rem" }, children: [
9573
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("strong", { children: "Create User" }),
9574
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("label", { children: [
8151
9575
  "Email",
8152
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("input", { name: "email", required: true, type: "email" })
9576
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("input", { name: "email", required: true, type: "email" })
8153
9577
  ] }),
8154
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
9578
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("label", { children: [
8155
9579
  "Full Name",
8156
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("input", { name: "fullName", type: "text" })
9580
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("input", { name: "fullName", type: "text" })
8157
9581
  ] }),
8158
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
9582
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("label", { children: [
8159
9583
  "Password",
8160
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("input", { name: "password", required: true, type: "password" })
9584
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("input", { name: "password", required: true, type: "password" })
8161
9585
  ] }),
8162
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
9586
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("label", { children: [
8163
9587
  "Role",
8164
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("select", { defaultValue: "editor", name: "role", children: [
8165
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: "admin", children: "admin" }),
8166
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: "editor", children: "editor" }),
8167
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: "client", children: "client" })
8168
- ] })
9588
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("select", { defaultValue: "editor", name: "role", children: userRoles.map((role) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: role, children: role }, role)) })
8169
9589
  ] }),
8170
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("button", { disabled: createSubmitting, type: "submit", children: createSubmitting ? "Creating..." : "Create User" })
9590
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("button", { disabled: createSubmitting, type: "submit", children: createSubmitting ? "Creating..." : "Create User" })
8171
9591
  ] }),
8172
- loading ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-list-meta", children: "Loading..." }) : null,
8173
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-list", children: docs.map((doc) => {
9592
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "orion-admin-list-meta", children: "Loading..." }) : null,
9593
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "orion-admin-list", children: docs.map((doc) => {
8174
9594
  const id = typeof doc.id === "string" || typeof doc.id === "number" ? String(doc.id) : "";
8175
9595
  if (!id) return null;
8176
9596
  const email = typeof doc.email === "string" ? doc.email : `user-${id}`;
8177
9597
  const fullName = typeof doc.fullName === "string" ? doc.fullName : "";
8178
9598
  const currentRole = typeof doc.role === "string" ? normalizeRole(doc.role) : "editor";
8179
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-list-item", children: [
8180
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { children: [
8181
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: email }),
8182
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-list-meta", children: fullName || "No full name set" })
9599
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "orion-admin-list-item", children: [
9600
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { children: [
9601
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("strong", { children: email }),
9602
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "orion-admin-list-meta", children: fullName || "No full name set" })
8183
9603
  ] }),
8184
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("form", { className: "orion-admin-inline-actions", onSubmit: updateUserRole, children: [
8185
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("input", { name: "id", type: "hidden", value: id }),
8186
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("select", { defaultValue: currentRole, name: "role", children: [
8187
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: "admin", children: "admin" }),
8188
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: "editor", children: "editor" }),
8189
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: "client", children: "client" })
8190
- ] }),
8191
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("button", { disabled: updatingUserID === id, type: "submit", children: updatingUserID === id ? "Updating..." : "Update" })
9604
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("form", { className: "orion-admin-inline-actions", onSubmit: updateUserRole, children: [
9605
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("input", { name: "id", type: "hidden", value: id }),
9606
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("select", { defaultValue: currentRole, name: "role", children: userRoles.map((role) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: role, children: role }, role)) }),
9607
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("button", { disabled: updatingUserID === id, type: "submit", children: updatingUserID === id ? "Updating..." : "Update" })
8192
9608
  ] })
8193
9609
  ] }, id);
8194
9610
  }) })
@@ -8199,14 +9615,14 @@ function AdminStudioToolsView(props) {
8199
9615
 
8200
9616
  // src/admin/components/studio/OpenInStudioMenuItem.tsx
8201
9617
  var import_ui13 = require("@payloadcms/ui");
8202
- var import_jsx_runtime42 = require("react/jsx-runtime");
9618
+ var import_jsx_runtime45 = require("react/jsx-runtime");
8203
9619
  function OpenInStudioMenuItem({ pagesPathBase = "/pages" }) {
8204
9620
  const documentInfo = (0, import_ui13.useDocumentInfo)();
8205
9621
  const id = documentInfo?.id;
8206
9622
  if (!id) {
8207
9623
  return null;
8208
9624
  }
8209
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
9625
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
8210
9626
  "a",
8211
9627
  {
8212
9628
  href: `${pagesPathBase}/${id}`,
@@ -8225,19 +9641,19 @@ function OpenInStudioMenuItem({ pagesPathBase = "/pages" }) {
8225
9641
  }
8226
9642
 
8227
9643
  // src/admin/components/studio/PageEditRedirectToStudio.tsx
8228
- var import_react33 = require("react");
9644
+ var import_react36 = require("react");
8229
9645
  var import_ui14 = require("@payloadcms/ui");
8230
- var import_jsx_runtime43 = require("react/jsx-runtime");
9646
+ var import_jsx_runtime46 = require("react/jsx-runtime");
8231
9647
  function PageEditRedirectToStudio({ pagesPathBase = "/pages" }) {
8232
9648
  const documentInfo = (0, import_ui14.useDocumentInfo)();
8233
9649
  const id = documentInfo?.id;
8234
- (0, import_react33.useEffect)(() => {
9650
+ (0, import_react36.useEffect)(() => {
8235
9651
  if (!id) {
8236
9652
  return;
8237
9653
  }
8238
9654
  window.location.replace(`${pagesPathBase}/${id}`);
8239
9655
  }, [id, pagesPathBase]);
8240
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
9656
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
8241
9657
  "div",
8242
9658
  {
8243
9659
  style: {
@@ -8249,18 +9665,61 @@ function PageEditRedirectToStudio({ pagesPathBase = "/pages" }) {
8249
9665
  minHeight: "50vh"
8250
9666
  },
8251
9667
  children: [
8252
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("h2", { style: { margin: 0 }, children: "Opening Editor..." }),
8253
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { style: { color: "var(--theme-elevation-600)", margin: 0 }, children: "Redirecting to the custom page editor." }),
8254
- id ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("a", { href: `${pagesPathBase}/${id}`, children: "Continue to Editor" }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("a", { href: pagesPathBase, children: "Open Pages" })
9668
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("h2", { style: { margin: 0 }, children: "Opening Editor..." }),
9669
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("p", { style: { color: "var(--theme-elevation-600)", margin: 0 }, children: "Redirecting to the custom page editor." }),
9670
+ id ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("a", { href: `${pagesPathBase}/${id}`, children: "Continue to Editor" }) : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("a", { href: pagesPathBase, children: "Open Pages" })
8255
9671
  ]
8256
9672
  }
8257
9673
  );
8258
9674
  }
8259
9675
 
8260
- // src/admin/components/studio/StudioBackBreadcrumb.tsx
8261
- var import_react34 = require("react");
9676
+ // src/admin/components/studio/StudioDocumentRedirect.tsx
9677
+ var import_react37 = require("react");
8262
9678
  var import_ui15 = require("@payloadcms/ui");
8263
- var import_jsx_runtime44 = require("react/jsx-runtime");
9679
+ var import_jsx_runtime47 = require("react/jsx-runtime");
9680
+ function StudioDocumentRedirect({
9681
+ description = "Redirecting to the Studio view.",
9682
+ emptyHref,
9683
+ emptyLabel = "Open Studio",
9684
+ pathBase = "/forms",
9685
+ title = "Opening Studio..."
9686
+ }) {
9687
+ const adminBasePath = useAdminBasePath();
9688
+ const documentInfo = (0, import_ui15.useDocumentInfo)();
9689
+ const id = documentInfo?.id;
9690
+ const fallbackHref = resolveAdminPath(adminBasePath, emptyHref || pathBase);
9691
+ (0, import_react37.useEffect)(() => {
9692
+ if (!id) {
9693
+ return;
9694
+ }
9695
+ const targetHref = resolveAdminPath(adminBasePath, `${pathBase}/${encodeURIComponent(String(id))}`);
9696
+ window.location.replace(targetHref);
9697
+ }, [adminBasePath, id, pathBase]);
9698
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
9699
+ "div",
9700
+ {
9701
+ style: {
9702
+ alignItems: "center",
9703
+ display: "flex",
9704
+ flexDirection: "column",
9705
+ gap: "0.75rem",
9706
+ justifyContent: "center",
9707
+ minHeight: "50vh",
9708
+ textAlign: "center"
9709
+ },
9710
+ children: [
9711
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("h2", { style: { margin: 0 }, children: title }),
9712
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("p", { style: { color: "var(--theme-elevation-600)", margin: 0 }, children: description }),
9713
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("a", { href: fallbackHref, children: emptyLabel })
9714
+ ]
9715
+ }
9716
+ );
9717
+ }
9718
+
9719
+ // src/admin/components/studio/StudioBackBreadcrumb.tsx
9720
+ var import_react38 = require("react");
9721
+ var import_ui16 = require("@payloadcms/ui");
9722
+ var import_jsx_runtime48 = require("react/jsx-runtime");
8264
9723
  var toTitle = (slug) => slug.split("-").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
8265
9724
  var buildNav = (pathname, adminBasePath) => {
8266
9725
  if (pathname.includes("/globals/")) {
@@ -8305,8 +9764,8 @@ var buildNav = (pathname, adminBasePath) => {
8305
9764
  };
8306
9765
  function StudioBackBreadcrumb() {
8307
9766
  const adminBasePath = useAdminBasePath();
8308
- const [pathname, setPathname] = (0, import_react34.useState)("");
8309
- (0, import_react34.useEffect)(() => {
9767
+ const [pathname, setPathname] = (0, import_react38.useState)("");
9768
+ (0, import_react38.useEffect)(() => {
8310
9769
  const update = () => setPathname(window.location.pathname);
8311
9770
  update();
8312
9771
  window.addEventListener("popstate", update);
@@ -8314,13 +9773,13 @@ function StudioBackBreadcrumb() {
8314
9773
  }, []);
8315
9774
  const nav = buildNav(pathname, adminBasePath);
8316
9775
  if (!nav) return null;
8317
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_ui15.SetStepNav, { nav });
9776
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui16.SetStepNav, { nav });
8318
9777
  }
8319
9778
 
8320
9779
  // src/admin/components/studio/StudioContactFormRedirect.tsx
8321
- var import_react35 = require("react");
8322
- var import_jsx_runtime45 = require("react/jsx-runtime");
8323
- var getPropString14 = (props, key, fallback) => {
9780
+ var import_react39 = require("react");
9781
+ var import_jsx_runtime49 = require("react/jsx-runtime");
9782
+ var getPropString15 = (props, key, fallback) => {
8324
9783
  if (!props || typeof props !== "object") return fallback;
8325
9784
  const direct = props[key];
8326
9785
  if (typeof direct === "string" && direct.length > 0) return direct;
@@ -8333,13 +9792,13 @@ var getPropString14 = (props, key, fallback) => {
8333
9792
  };
8334
9793
  function StudioContactFormRedirect(props) {
8335
9794
  const adminBasePath = useAdminBasePath();
8336
- const studioContactFormPath = getPropString14(props, "studioContactFormPath", "/contact-form");
9795
+ const studioContactFormPath = getPropString15(props, "studioContactFormPath", "/contact-form");
8337
9796
  const targetPath = resolveAdminPath(adminBasePath, studioContactFormPath);
8338
- (0, import_react35.useEffect)(() => {
9797
+ (0, import_react39.useEffect)(() => {
8339
9798
  if (window.location.pathname === targetPath) return;
8340
9799
  window.location.replace(targetPath);
8341
9800
  }, [targetPath]);
8342
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
9801
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
8343
9802
  "div",
8344
9803
  {
8345
9804
  style: {
@@ -8352,8 +9811,8 @@ function StudioContactFormRedirect(props) {
8352
9811
  minHeight: "40vh"
8353
9812
  },
8354
9813
  children: [
8355
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h2", { style: { margin: 0 }, children: "Opening Contact Form Editor..." }),
8356
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("a", { href: targetPath, children: "Continue" })
9814
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("h2", { style: { margin: 0 }, children: "Opening Contact Form Editor..." }),
9815
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("a", { href: targetPath, children: "Continue" })
8357
9816
  ]
8358
9817
  }
8359
9818
  );
@@ -8365,6 +9824,9 @@ function StudioContactFormRedirect(props) {
8365
9824
  AdminStudioContactFormView,
8366
9825
  AdminStudioDashboard,
8367
9826
  AdminStudioFooterGlobalView,
9827
+ AdminStudioFormDetailView,
9828
+ AdminStudioFormSubmissionView,
9829
+ AdminStudioFormUploadView,
8368
9830
  AdminStudioFormsView,
8369
9831
  AdminStudioGlobalsView,
8370
9832
  AdminStudioHeaderGlobalView,
@@ -8390,6 +9852,7 @@ function StudioContactFormRedirect(props) {
8390
9852
  StatusBadge,
8391
9853
  StudioBackBreadcrumb,
8392
9854
  StudioContactFormRedirect,
9855
+ StudioDocumentRedirect,
8393
9856
  StudioSectionLayout,
8394
9857
  ThemeProvider,
8395
9858
  ThemeSwitcher,