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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +6 -1
  2. package/bin/init.js +329 -0
  3. package/dist/admin/client.js +2106 -585
  4. package/dist/admin/client.mjs +2161 -653
  5. package/dist/admin/index.d.mts +2 -2
  6. package/dist/admin/index.d.ts +2 -2
  7. package/dist/admin/index.js +190 -36
  8. package/dist/admin/index.mjs +2 -2
  9. package/dist/admin-app/client.js +14 -5
  10. package/dist/admin-app/client.mjs +1 -1
  11. package/dist/admin-app/index.d.mts +2 -2
  12. package/dist/admin-app/index.d.ts +2 -2
  13. package/dist/admin-app/styles.css +361 -41
  14. package/dist/admin.css +98 -2
  15. package/dist/blocks/index.mjs +1 -2
  16. package/dist/builder-v2/client.d.mts +18 -0
  17. package/dist/builder-v2/client.d.ts +18 -0
  18. package/dist/builder-v2/client.js +4287 -0
  19. package/dist/builder-v2/client.mjs +4162 -0
  20. package/dist/builder-v2/index.d.mts +249 -0
  21. package/dist/builder-v2/index.d.ts +249 -0
  22. package/dist/builder-v2/index.js +836 -0
  23. package/dist/builder-v2/index.mjs +786 -0
  24. package/dist/builder-v2/styles.css +2705 -0
  25. package/dist/{chunk-PF3EBZXF.mjs → chunk-7ZMXZRBP.mjs} +39 -3
  26. package/dist/{chunk-XKUTZ7IU.mjs → chunk-DTHBPJXU.mjs} +246 -25
  27. package/dist/{chunk-JQAHXYAM.mjs → chunk-KMYMSR7W.mjs} +163 -3
  28. package/dist/{chunk-WLOPFFN2.mjs → chunk-MMJNHBOF.mjs} +193 -39
  29. package/dist/{chunk-KPIX7OSV.mjs → chunk-NF37A575.mjs} +14 -5
  30. package/dist/{chunk-OTHERBGX.mjs → chunk-OF6BATTO.mjs} +57 -112
  31. package/dist/chunk-VA545CHJ.mjs +202 -0
  32. package/dist/forms/index.d.mts +25 -0
  33. package/dist/forms/index.d.ts +25 -0
  34. package/dist/forms/index.js +237 -0
  35. package/dist/forms/index.mjs +25 -0
  36. package/dist/forms/server.d.mts +35 -0
  37. package/dist/forms/server.d.ts +35 -0
  38. package/dist/forms/server.js +442 -0
  39. package/dist/forms/server.mjs +228 -0
  40. package/dist/{index-Crx_MtPw.d.ts → index-0xXWuOuz.d.ts} +38 -6
  41. package/dist/{index-Cv-6qnrw.d.mts → index-BU82akSL.d.mts} +38 -6
  42. package/dist/{index-Bm2SaC3r.d.mts → index-BbTcimgH.d.mts} +4 -2
  43. package/dist/{index-D8BNfUJb.d.mts → index-Cen-9wcc.d.mts} +17 -5
  44. package/dist/{index-52HdVLQq.d.ts → index-DAdN56fM.d.ts} +1 -1
  45. package/dist/{index-CkT_eyhK.d.ts → index-DV-nW43e.d.ts} +4 -2
  46. package/dist/{index-DEQC3Dwj.d.mts → index-G_uTNffQ.d.mts} +1 -1
  47. package/dist/{index-DD_E2UfJ.d.ts → index-gxcMPpm-.d.ts} +17 -5
  48. package/dist/index.d.mts +5 -5
  49. package/dist/index.d.ts +5 -5
  50. package/dist/index.js +522 -171
  51. package/dist/index.mjs +10 -11
  52. package/dist/nextjs/index.d.mts +1 -1
  53. package/dist/nextjs/index.d.ts +1 -1
  54. package/dist/nextjs/index.js +95 -114
  55. package/dist/nextjs/index.mjs +2 -2
  56. package/dist/{sitePreviewTypes-BkHCWxNW.d.mts → sitePreviewTypes-BrJwGzJj.d.mts} +1 -1
  57. package/dist/{sitePreviewTypes-BkHCWxNW.d.ts → sitePreviewTypes-BrJwGzJj.d.ts} +1 -1
  58. package/dist/studio-pages/builder.css +66 -5
  59. package/dist/studio-pages/client.js +618 -73
  60. package/dist/studio-pages/client.mjs +641 -96
  61. package/dist/studio-pages/index.d.mts +1 -1
  62. package/dist/studio-pages/index.d.ts +1 -1
  63. package/dist/studio-pages/index.js +1893 -24
  64. package/dist/studio-pages/index.mjs +11 -3
  65. package/package.json +38 -3
  66. package/dist/chunk-OQSEJXC4.mjs +0 -166
@@ -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",
@@ -1424,27 +1448,13 @@ function AdminLoginIntro({ brandName = "Orion Studio", logoUrl } = {}) {
1424
1448
  const branding = useSiteBranding(brandName, logoUrl);
1425
1449
  const resolvedName = branding.siteName || brandName;
1426
1450
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "orion-admin-login-intro", children: [
1427
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "orion-admin-login-eyebrow", children: "Studio Access" }),
1451
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "orion-admin-login-eyebrow", children: "Private Admin" }),
1428
1452
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("h1", { children: [
1429
- "Manage ",
1430
1453
  resolvedName,
1431
- " without losing the site's voice."
1454
+ " admin"
1432
1455
  ] }),
1433
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: "Sign in to update content, review leads, and keep the public site aligned with the same brand experience your visitors already know." }),
1434
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "orion-admin-login-note-grid", children: [
1435
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("article", { className: "orion-admin-login-note", children: [
1436
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: "Branded workspace" }),
1437
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "The admin mirrors the live site instead of dropping editors into a generic CMS shell." })
1438
- ] }),
1439
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("article", { className: "orion-admin-login-note", children: [
1440
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: "One editorial flow" }),
1441
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Pages, globals, media, forms, and analytics stay in one place once you are inside." })
1442
- ] }),
1443
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("article", { className: "orion-admin-login-note", children: [
1444
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: "Protected entry" }),
1445
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Only authorized administrators and editors can access this workspace." })
1446
- ] })
1447
- ] })
1456
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: "Sign in to update pages, review forms, manage media, and adjust site settings." }),
1457
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "orion-admin-login-caption", children: "For owners and authorized team members." })
1448
1458
  ] });
1449
1459
  }
1450
1460
 
@@ -2568,7 +2578,7 @@ var navItemIsActive = (pathname, item) => {
2568
2578
  };
2569
2579
 
2570
2580
  // src/shared/studioSections.ts
2571
- var studioRoles = /* @__PURE__ */ new Set(["admin", "editor", "client"]);
2581
+ var studioRoles = /* @__PURE__ */ new Set(["admin", "developer", "editor", "client"]);
2572
2582
  var studioIcons = new Set(adminNavIcons);
2573
2583
  var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
2574
2584
  var isAbsoluteExternalURL2 = (value) => /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(value) || value.startsWith("//");
@@ -2766,7 +2776,7 @@ var buildStudioNavItems = (props, adminBasePath) => {
2766
2776
  icon: "tools",
2767
2777
  label: "Admin Tools",
2768
2778
  matchPrefixes: [toolsPath, resolveAdminPath(adminBasePath, "/collections/users")],
2769
- roles: ["admin"]
2779
+ roles: ["admin", "developer"]
2770
2780
  };
2771
2781
  const extensionItems = sections.map((section) => ({
2772
2782
  href: resolveAdminPath(adminBasePath, section.href),
@@ -2863,8 +2873,26 @@ function NavIcon({ sectionID }) {
2863
2873
  return null;
2864
2874
  }
2865
2875
  }
2876
+ function LogoutIcon() {
2877
+ const props = {
2878
+ fill: "none",
2879
+ height: iconSize2,
2880
+ stroke: "currentColor",
2881
+ strokeLinecap: "round",
2882
+ strokeLinejoin: "round",
2883
+ strokeWidth: 2,
2884
+ viewBox: "0 0 24 24",
2885
+ width: iconSize2
2886
+ };
2887
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { ...props, "aria-hidden": "true", children: [
2888
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4" }),
2889
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("polyline", { points: "10 17 5 12 10 7" }),
2890
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("line", { x1: "5", y1: "12", x2: "17", y2: "12" })
2891
+ ] });
2892
+ }
2866
2893
  function AdminStudioNav(props) {
2867
2894
  const { user } = (0, import_ui3.useAuth)();
2895
+ const [loggingOut, setLoggingOut] = (0, import_react13.useState)(false);
2868
2896
  const brandName = getPropString(props, "brandName", "Orion Studio");
2869
2897
  const logoUrl = getPropString(props, "logoUrl", "");
2870
2898
  const compact = getPropBoolean(props, "compact", false);
@@ -2875,6 +2903,18 @@ function AdminStudioNav(props) {
2875
2903
  const dashboardPath = adminBasePath;
2876
2904
  const userRole = readUserRole(user);
2877
2905
  const links = (0, import_react13.useMemo)(() => buildStudioNavItems(props, adminBasePath), [adminBasePath, props]);
2906
+ const logout = async () => {
2907
+ setLoggingOut(true);
2908
+ try {
2909
+ await fetch("/api/users/logout", {
2910
+ credentials: "include",
2911
+ method: "POST"
2912
+ });
2913
+ window.location.href = `${adminBasePath}/login`;
2914
+ } finally {
2915
+ setLoggingOut(false);
2916
+ }
2917
+ };
2878
2918
  if (isStudioShellRoute(pathname, props, adminBasePath)) {
2879
2919
  return null;
2880
2920
  }
@@ -2965,7 +3005,38 @@ function AdminStudioNav(props) {
2965
3005
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { color: "var(--theme-elevation-700)", fontSize: "0.85rem" }, children: "Signed in as" }),
2966
3006
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { fontWeight: 800, marginBottom: "0.55rem" }, children: typeof user?.email === "string" ? user.email : "User" })
2967
3007
  ] }) : null,
2968
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_ui3.Logout, {})
3008
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
3009
+ "button",
3010
+ {
3011
+ "aria-label": "Log out",
3012
+ disabled: loggingOut,
3013
+ onClick: () => void logout(),
3014
+ style: {
3015
+ alignItems: "center",
3016
+ background: "transparent",
3017
+ border: "1px solid var(--theme-elevation-150)",
3018
+ borderRadius: 10,
3019
+ color: "var(--theme-elevation-900)",
3020
+ cursor: loggingOut ? "not-allowed" : "pointer",
3021
+ display: "inline-flex",
3022
+ font: "inherit",
3023
+ fontWeight: 800,
3024
+ gap: compact ? 0 : "0.45rem",
3025
+ justifyContent: "center",
3026
+ minHeight: compact ? 48 : 34,
3027
+ minWidth: compact ? 48 : 0,
3028
+ opacity: loggingOut ? 0.55 : 1,
3029
+ padding: compact ? 0 : "0.4rem 0.62rem",
3030
+ width: compact ? 48 : "auto"
3031
+ },
3032
+ title: "Log out",
3033
+ type: "button",
3034
+ children: [
3035
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(LogoutIcon, {}),
3036
+ !compact ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { children: loggingOut ? "Logging out..." : "Log out" }) : null
3037
+ ]
3038
+ }
3039
+ )
2969
3040
  ]
2970
3041
  }
2971
3042
  )
@@ -3038,6 +3109,14 @@ function NavIcon2({ name }) {
3038
3109
  return null;
3039
3110
  }
3040
3111
  }
3112
+ function LogoutIcon2() {
3113
+ const props = { width: iconSize3, height: iconSize3, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", style: iconStyle };
3114
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("svg", { ...props, "aria-hidden": "true", children: [
3115
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4" }),
3116
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("polyline", { points: "10 17 5 12 10 7" }),
3117
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("line", { x1: "5", y1: "12", x2: "17", y2: "12" })
3118
+ ] });
3119
+ }
3041
3120
  function AdminShellClient({
3042
3121
  children,
3043
3122
  brandName,
@@ -3049,14 +3128,12 @@ function AdminShellClient({
3049
3128
  onLogout,
3050
3129
  storageKey = "orion-admin-shell-collapsed"
3051
3130
  }) {
3052
- const [collapsed, setCollapsed] = (0, import_react14.useState)(false);
3131
+ const [collapsed, setCollapsed] = (0, import_react14.useState)(true);
3053
3132
  const [loggingOut, setLoggingOut] = (0, import_react14.useState)(false);
3054
3133
  (0, import_react14.useEffect)(() => {
3055
3134
  try {
3056
3135
  const stored = window.localStorage.getItem(storageKey);
3057
- if (stored === "1") {
3058
- setCollapsed(true);
3059
- }
3136
+ setCollapsed(stored === "1");
3060
3137
  } catch {
3061
3138
  }
3062
3139
  }, [storageKey]);
@@ -3118,7 +3195,10 @@ function AdminShellClient({
3118
3195
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "orion-admin-user-label", children: "Signed in as" }),
3119
3196
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "orion-admin-user-email", children: userEmail })
3120
3197
  ] }) : null,
3121
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { className: "orion-admin-logout", disabled: loggingOut, onClick: handleLogout, type: "button", children: loggingOut ? "..." : "Log out" })
3198
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { className: "orion-admin-logout", disabled: loggingOut, onClick: handleLogout, type: "button", children: [
3199
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(LogoutIcon2, {}),
3200
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: loggingOut ? "Logging out..." : "Log out" })
3201
+ ] })
3122
3202
  ] })
3123
3203
  ] }),
3124
3204
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("main", { className: "orion-admin-main", children })
@@ -3207,9 +3287,9 @@ var import_react16 = require("react");
3207
3287
  var import_link = __toESM(require("next/link"));
3208
3288
  var import_jsx_runtime21 = require("react/jsx-runtime");
3209
3289
  var SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1e3;
3210
- var isRole = (value) => value === "admin" || value === "editor" || value === "client";
3211
- var canReviewForms = (role) => role === "admin" || role === "editor";
3212
- var canCreatePages = (role) => role === "admin" || role === "editor";
3290
+ var isRole = (value) => value === "admin" || value === "client" || value === "developer" || value === "editor";
3291
+ var canReviewForms = (role) => role === "admin" || role === "developer" || role === "editor";
3292
+ var canCreatePages = (role) => role === "admin" || role === "developer" || role === "editor";
3213
3293
  var canAccess = (role, roles) => {
3214
3294
  if (!roles || roles.length === 0) {
3215
3295
  return true;
@@ -3685,7 +3765,7 @@ function AdminStudioDashboardClient({
3685
3765
  label: "Manage Media",
3686
3766
  tone: "ghost"
3687
3767
  });
3688
- if (role === "admin") {
3768
+ if (role === "admin" || role === "developer") {
3689
3769
  actions.push({
3690
3770
  description: "Manage users, roles, and fallback tools.",
3691
3771
  href: toolsPath,
@@ -3964,7 +4044,7 @@ var buildSectionLinks = (adminBasePath, sections, formsEnabled, globalsBasePath)
3964
4044
  href: resolveAdminPath2(adminBasePath, "/tools"),
3965
4045
  id: "admin-tools",
3966
4046
  label: "Admin Tools",
3967
- roles: ["admin"]
4047
+ roles: ["admin", "developer"]
3968
4048
  }
3969
4049
  ];
3970
4050
  const seen = /* @__PURE__ */ new Set();
@@ -4030,15 +4110,16 @@ function AdminStudioDashboard(rawProps) {
4030
4110
  }
4031
4111
 
4032
4112
  // src/admin/components/studio/AdminStudioPagesListView.tsx
4033
- var import_react17 = require("react");
4113
+ var import_react19 = require("react");
4034
4114
  var import_link2 = __toESM(require("next/link"));
4115
+ var import_navigation3 = require("next/navigation");
4116
+ var import_ui7 = require("@payloadcms/ui");
4117
+
4118
+ // src/admin/components/studio/AdminStudioNewPageView.tsx
4119
+ var import_react17 = require("react");
4035
4120
  var import_ui5 = require("@payloadcms/ui");
4036
4121
  var import_jsx_runtime23 = require("react/jsx-runtime");
4037
- var isAdmin = (user) => {
4038
- if (!user || typeof user !== "object") return false;
4039
- const role = user.role;
4040
- return typeof role === "string" && role === "admin";
4041
- };
4122
+ var pageTemplates = ["standard", "landing", "services", "contact"];
4042
4123
  var getPropString3 = (props, key, fallback) => {
4043
4124
  if (!props || typeof props !== "object") return fallback;
4044
4125
  const direct = props[key];
@@ -4050,83 +4131,107 @@ var getPropString3 = (props, key, fallback) => {
4050
4131
  }
4051
4132
  return fallback;
4052
4133
  };
4053
- function AdminStudioPagesListView(props) {
4134
+ var canManagePages = (user) => {
4135
+ if (!user || typeof user !== "object") return false;
4136
+ const role = user.role;
4137
+ return role === "admin" || role === "developer" || role === "editor";
4138
+ };
4139
+ var slugify = (value) => value.toLowerCase().trim().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-");
4140
+ function AdminStudioNewPageView(props) {
4054
4141
  const { user } = (0, import_ui5.useAuth)();
4055
- const pagesCollectionSlug = getPropString3(props, "pagesCollectionSlug", "pages");
4056
4142
  const adminBasePath = useAdminBasePath();
4057
- const newPagePath = resolveAdminPath(adminBasePath, "/pages/new");
4058
- const [loading, setLoading] = (0, import_react17.useState)(true);
4143
+ const pagesCollectionSlug = getPropString3(props, "pagesCollectionSlug", "pages");
4144
+ const [submitting, setSubmitting] = (0, import_react17.useState)(false);
4059
4145
  const [error, setError] = (0, import_react17.useState)(null);
4060
- const [docs, setDocs] = (0, import_react17.useState)([]);
4061
- const apiURL = (0, import_react17.useMemo)(() => {
4062
- const params = new URLSearchParams({
4063
- depth: "0",
4064
- limit: "100",
4065
- sort: "-updatedAt",
4066
- draft: "true"
4067
- });
4068
- return `/api/${pagesCollectionSlug}?${params.toString()}`;
4069
- }, [pagesCollectionSlug]);
4070
- (0, import_react17.useEffect)(() => {
4071
- let cancelled = false;
4072
- const run = async () => {
4073
- setLoading(true);
4074
- setError(null);
4075
- try {
4076
- const res = await fetch(apiURL, { credentials: "include" });
4077
- if (!res.ok) {
4078
- const body = await res.text();
4079
- throw new Error(body || "Failed to fetch pages");
4080
- }
4081
- const data = await res.json();
4082
- if (!cancelled) {
4083
- setDocs(Array.isArray(data.docs) ? data.docs : []);
4084
- }
4085
- } catch (err) {
4086
- if (!cancelled) {
4087
- setError(err instanceof Error ? err.message : "Failed to fetch pages");
4088
- }
4089
- } finally {
4090
- if (!cancelled) {
4091
- setLoading(false);
4092
- }
4146
+ if (!canManagePages(user)) {
4147
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4148
+ AdminPage,
4149
+ {
4150
+ breadcrumbs: [
4151
+ { label: "Dashboard", href: adminBasePath },
4152
+ { label: "Pages", href: resolveAdminPath(adminBasePath, "/pages") },
4153
+ { label: "New Page" }
4154
+ ],
4155
+ description: "You do not have access to create pages.",
4156
+ title: "New Page",
4157
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "orion-admin-card", children: [
4158
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("strong", { children: "Access denied" }),
4159
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: "This section is restricted to administrator, developer, and editor accounts." })
4160
+ ] })
4093
4161
  }
4094
- };
4095
- void run();
4096
- return () => {
4097
- cancelled = true;
4098
- };
4099
- }, [apiURL]);
4100
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
4162
+ ) });
4163
+ }
4164
+ const createPage = async (event) => {
4165
+ event.preventDefault();
4166
+ setSubmitting(true);
4167
+ setError(null);
4168
+ try {
4169
+ const formData = new FormData(event.currentTarget);
4170
+ const titleValue = String(formData.get("title") || "").trim();
4171
+ const slugValue = String(formData.get("slug") || "").trim();
4172
+ const templateValue = String(formData.get("template") || "standard").trim();
4173
+ const template = pageTemplates.includes(templateValue) ? templateValue : "standard";
4174
+ const title = titleValue || "Untitled Page";
4175
+ const slug = slugValue || slugify(title) || "untitled-page";
4176
+ const response = await fetch(`/api/${pagesCollectionSlug}`, {
4177
+ body: JSON.stringify({
4178
+ _status: "draft",
4179
+ slug,
4180
+ template,
4181
+ title
4182
+ }),
4183
+ credentials: "include",
4184
+ headers: {
4185
+ "Content-Type": "application/json"
4186
+ },
4187
+ method: "POST"
4188
+ });
4189
+ if (!response.ok) {
4190
+ throw new Error(`Failed to create page (${response.status}).`);
4191
+ }
4192
+ const payload = await response.json();
4193
+ const id = typeof payload.id === "string" || typeof payload.id === "number" ? String(payload.id) : "";
4194
+ if (!id) {
4195
+ throw new Error("Page created but no document ID was returned.");
4196
+ }
4197
+ window.location.assign(resolveAdminPath(adminBasePath, `/pages/${id}`));
4198
+ } catch (createError) {
4199
+ setError(createError instanceof Error ? createError.message : "Failed to create page.");
4200
+ } finally {
4201
+ setSubmitting(false);
4202
+ }
4203
+ };
4204
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4101
4205
  AdminPage,
4102
4206
  {
4103
- actions: isAdmin(user) ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_link2.default, { className: "orion-admin-action-button", href: newPagePath, children: "New Page" }) : null,
4104
4207
  breadcrumbs: [
4105
4208
  { label: "Dashboard", href: adminBasePath },
4106
- { label: "Pages" }
4209
+ { label: "Pages", href: resolveAdminPath(adminBasePath, "/pages") },
4210
+ { label: "New Page" }
4107
4211
  ],
4108
- description: "Open a page to edit it in the inline custom builder.",
4109
- title: "Pages",
4110
- children: [
4111
- loading ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "orion-admin-list-meta", children: "Loading..." }) : null,
4212
+ description: "Create a new page and open it in the custom editor.",
4213
+ title: "New Page",
4214
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("form", { className: "orion-admin-form", onSubmit: createPage, children: [
4112
4215
  error ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "orion-admin-error", children: error }) : null,
4113
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "orion-admin-list", children: [
4114
- !loading && !error && docs.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "orion-admin-card", children: [
4115
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("strong", { children: "No pages yet" }),
4116
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: "Create the first page to start building content." })
4117
- ] }) : null,
4118
- docs.map((doc) => {
4119
- const id = typeof doc.id === "string" || typeof doc.id === "number" ? String(doc.id) : "";
4120
- if (!id) return null;
4121
- const title = typeof doc.title === "string" ? doc.title : "Untitled Page";
4122
- const status = typeof doc._status === "string" ? doc._status : "draft";
4123
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_link2.default, { className: "orion-admin-list-item", href: resolveAdminPath(adminBasePath, `/pages/${id}`), children: [
4124
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("strong", { children: title }) }),
4125
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "orion-admin-pill", children: status })
4126
- ] }, id);
4127
- })
4128
- ] })
4129
- ]
4216
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { children: [
4217
+ "Title",
4218
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("input", { name: "title", placeholder: "Services", required: true, type: "text" })
4219
+ ] }),
4220
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { children: [
4221
+ "Slug",
4222
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("input", { name: "slug", placeholder: "services", type: "text" })
4223
+ ] }),
4224
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { children: [
4225
+ "Template",
4226
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("select", { defaultValue: "standard", name: "template", children: [
4227
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: "standard", children: "Standard" }),
4228
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: "landing", children: "Landing" }),
4229
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: "contact", children: "Contact" }),
4230
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: "services", children: "Services" })
4231
+ ] })
4232
+ ] }),
4233
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { disabled: submitting, type: "submit", children: submitting ? "Creating..." : "Create Page" })
4234
+ ] })
4130
4235
  }
4131
4236
  ) });
4132
4237
  }
@@ -4135,16 +4240,6 @@ function AdminStudioPagesListView(props) {
4135
4240
  var import_react18 = require("react");
4136
4241
  var import_ui6 = require("@payloadcms/ui");
4137
4242
  var import_jsx_runtime24 = require("react/jsx-runtime");
4138
- var isAdmin2 = (user) => {
4139
- if (!user || typeof user !== "object") return false;
4140
- const role = user.role;
4141
- return typeof role === "string" && role === "admin";
4142
- };
4143
- var isEditor = (user) => {
4144
- if (!user || typeof user !== "object") return false;
4145
- const role = user.role;
4146
- return typeof role === "string" && role === "editor";
4147
- };
4148
4243
  var getPropString4 = (props, key, fallback) => {
4149
4244
  if (!props || typeof props !== "object") return fallback;
4150
4245
  const direct = props[key];
@@ -4172,14 +4267,8 @@ var getPageIDFromPathname = (pathname) => {
4172
4267
  return pagePart ? decodeURIComponent(pagePart) : null;
4173
4268
  };
4174
4269
  function AdminStudioPageEditView(props) {
4175
- const { user } = (0, import_ui6.useAuth)();
4176
4270
  const adminBasePath = useAdminBasePath();
4177
4271
  const iframeRef = (0, import_react18.useRef)(null);
4178
- const [saving, setSaving] = (0, import_react18.useState)(null);
4179
- const [dirty, setDirty] = (0, import_react18.useState)(false);
4180
- const [hasUnpublishedChanges, setHasUnpublishedChanges] = (0, import_react18.useState)(false);
4181
- const [canUndo, setCanUndo] = (0, import_react18.useState)(false);
4182
- const [canRedo, setCanRedo] = (0, import_react18.useState)(false);
4183
4272
  const builderBasePath = getPropString4(props, "builderBasePath", "/builder");
4184
4273
  const pagesPath = resolveAdminPath(adminBasePath, "/pages");
4185
4274
  const pageIDFromParams = (0, import_react18.useMemo)(() => getParam(props.params, "id"), [props.params]);
@@ -4196,96 +4285,6 @@ function AdminStudioPageEditView(props) {
4196
4285
  }
4197
4286
  setDidResolvePathFallback(true);
4198
4287
  }, [pageIDFromParams]);
4199
- const canPublish = isAdmin2(user) || isEditor(user);
4200
- const refreshUnpublishedState = async (id) => {
4201
- try {
4202
- const response = await fetch(
4203
- `/api/pages/versions?depth=0&limit=25&sort=-updatedAt&where[parent][equals]=${encodeURIComponent(id)}`,
4204
- {
4205
- credentials: "include"
4206
- }
4207
- );
4208
- if (!response.ok) {
4209
- return;
4210
- }
4211
- const payload = await response.json();
4212
- const docs = Array.isArray(payload.docs) ? payload.docs : [];
4213
- let latestDraft = 0;
4214
- let latestPublished = 0;
4215
- docs.forEach((doc) => {
4216
- const status = doc.version?._status;
4217
- const millis = typeof doc.updatedAt === "string" ? Date.parse(doc.updatedAt) : Number.NaN;
4218
- if (!Number.isFinite(millis)) {
4219
- return;
4220
- }
4221
- if (status === "draft") {
4222
- latestDraft = Math.max(latestDraft, millis);
4223
- }
4224
- if (status === "published") {
4225
- latestPublished = Math.max(latestPublished, millis);
4226
- }
4227
- });
4228
- setHasUnpublishedChanges(latestDraft > 0 && latestDraft >= latestPublished);
4229
- } catch {
4230
- }
4231
- };
4232
- (0, import_react18.useEffect)(() => {
4233
- if (!pageID) {
4234
- return;
4235
- }
4236
- void refreshUnpublishedState(pageID);
4237
- }, [pageID]);
4238
- const requestSave = (status) => {
4239
- const iframe = iframeRef.current;
4240
- if (!iframe?.contentWindow) {
4241
- import_ui6.toast.error("Editor is not ready yet. Please try again.");
4242
- return;
4243
- }
4244
- setSaving(status);
4245
- iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type: "save", status }, "*");
4246
- };
4247
- const requestHistoryAction = (type) => {
4248
- const iframe = iframeRef.current;
4249
- if (!iframe?.contentWindow) {
4250
- import_ui6.toast.error("Editor is not ready yet. Please try again.");
4251
- return;
4252
- }
4253
- iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type }, "*");
4254
- };
4255
- (0, import_react18.useEffect)(() => {
4256
- const onMessage = (event) => {
4257
- const data = event.data;
4258
- if (!data || data.source !== "payload-visual-builder-child" || typeof data.type !== "string") {
4259
- return;
4260
- }
4261
- if (data.type === "dirty-state") {
4262
- setDirty(Boolean(data.dirty));
4263
- return;
4264
- }
4265
- if (data.type === "history-state") {
4266
- setCanUndo(Boolean(data.canUndo));
4267
- setCanRedo(Boolean(data.canRedo));
4268
- return;
4269
- }
4270
- if (data.type === "save-result") {
4271
- setSaving(null);
4272
- if (data.ok) {
4273
- if (data.status === "draft") {
4274
- setHasUnpublishedChanges(true);
4275
- } else if (data.status === "published") {
4276
- setHasUnpublishedChanges(false);
4277
- } else if (pageID) {
4278
- void refreshUnpublishedState(pageID);
4279
- }
4280
- import_ui6.toast.success(typeof data.message === "string" ? data.message : "Saved.");
4281
- } else {
4282
- import_ui6.toast.error(typeof data.message === "string" ? data.message : "Save failed.");
4283
- }
4284
- }
4285
- };
4286
- window.addEventListener("message", onMessage);
4287
- return () => window.removeEventListener("message", onMessage);
4288
- }, []);
4289
4288
  if (!pageID && !didResolvePathFallback) {
4290
4289
  return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
4291
4290
  /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
@@ -4326,155 +4325,25 @@ function AdminStudioPageEditView(props) {
4326
4325
  ]
4327
4326
  }
4328
4327
  ),
4329
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { display: "grid", gridTemplateRows: "auto 1fr", height: "calc(100vh - 120px)" }, children: [
4330
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
4331
- "div",
4332
- {
4333
- style: {
4334
- alignItems: "center",
4335
- background: "var(--theme-elevation-0)",
4336
- borderBottom: "1px solid var(--theme-elevation-150)",
4337
- display: "flex",
4338
- gap: "0.6rem",
4339
- justifyContent: "space-between",
4340
- padding: "0.65rem 0.9rem",
4341
- position: "sticky",
4342
- top: 0,
4343
- zIndex: 20
4344
- },
4345
- children: [
4346
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { minWidth: 0 }, children: [
4347
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { fontWeight: 900 }, children: "Page Editor" }),
4348
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
4349
- "div",
4350
- {
4351
- style: {
4352
- color: "var(--theme-elevation-600)",
4353
- fontSize: "0.85rem",
4354
- overflow: "hidden",
4355
- textOverflow: "ellipsis"
4356
- },
4357
- children: [
4358
- "Editing: ",
4359
- pageID
4360
- ]
4361
- }
4362
- )
4363
- ] }),
4364
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { alignItems: "center", display: "flex", gap: "0.5rem" }, children: [
4365
- /* @__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" }),
4366
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4367
- "div",
4368
- {
4369
- style: {
4370
- background: hasUnpublishedChanges ? "#fff3cd" : "var(--theme-success-50)",
4371
- border: `1px solid ${hasUnpublishedChanges ? "#f0c36d" : "var(--theme-success-300)"}`,
4372
- borderRadius: 999,
4373
- color: hasUnpublishedChanges ? "#6a4a00" : "var(--theme-success-700)",
4374
- fontSize: "0.75rem",
4375
- fontWeight: 800,
4376
- padding: "0.2rem 0.55rem",
4377
- whiteSpace: "nowrap"
4378
- },
4379
- title: hasUnpublishedChanges ? "There are saved draft changes not yet published." : "The live page matches the latest published content.",
4380
- children: hasUnpublishedChanges ? "Unpublished draft changes" : "Live is up to date"
4381
- }
4382
- ),
4383
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4384
- "button",
4385
- {
4386
- disabled: !canUndo,
4387
- onClick: () => requestHistoryAction("undo"),
4388
- style: {
4389
- border: "1px solid var(--theme-elevation-300)",
4390
- borderRadius: 12,
4391
- cursor: canUndo ? "pointer" : "not-allowed",
4392
- fontWeight: 800,
4393
- padding: "0.5rem 0.65rem"
4394
- },
4395
- type: "button",
4396
- children: "Undo"
4397
- }
4398
- ),
4399
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4400
- "button",
4401
- {
4402
- disabled: !canRedo,
4403
- onClick: () => requestHistoryAction("redo"),
4404
- style: {
4405
- border: "1px solid var(--theme-elevation-300)",
4406
- borderRadius: 12,
4407
- cursor: canRedo ? "pointer" : "not-allowed",
4408
- fontWeight: 800,
4409
- padding: "0.5rem 0.65rem"
4410
- },
4411
- type: "button",
4412
- children: "Redo"
4413
- }
4414
- ),
4415
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4416
- "button",
4417
- {
4418
- disabled: saving !== null,
4419
- onClick: () => requestSave("draft"),
4420
- style: {
4421
- border: "1px solid var(--theme-elevation-300)",
4422
- borderRadius: 12,
4423
- cursor: saving ? "not-allowed" : "pointer",
4424
- fontWeight: 800,
4425
- padding: "0.5rem 0.75rem"
4426
- },
4427
- type: "button",
4428
- children: saving === "draft" ? "Saving\u2026" : "Save Draft"
4429
- }
4430
- ),
4431
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4432
- "button",
4433
- {
4434
- disabled: !canPublish || saving !== null,
4435
- onClick: () => requestSave("published"),
4436
- style: {
4437
- background: canPublish ? "var(--theme-success-700)" : "var(--theme-elevation-300)",
4438
- border: "none",
4439
- borderRadius: 12,
4440
- color: canPublish ? "var(--theme-elevation-0)" : "var(--theme-elevation-700)",
4441
- cursor: !canPublish || saving ? "not-allowed" : "pointer",
4442
- fontWeight: 900,
4443
- padding: "0.5rem 0.75rem"
4444
- },
4445
- type: "button",
4446
- title: !canPublish ? "You do not have publish permissions." : void 0,
4447
- children: saving === "published" ? "Publishing\u2026" : "Publish"
4448
- }
4449
- )
4450
- ] })
4451
- ]
4452
- }
4453
- ),
4454
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4455
- "iframe",
4456
- {
4457
- ref: iframeRef,
4458
- src: `${builderBasePath.replace(/\/$/, "")}/${pageID}`,
4459
- style: { border: "none", height: "100%", width: "100%" },
4460
- title: "Page Builder",
4461
- onLoad: () => {
4462
- const iframe = iframeRef.current;
4463
- if (!iframe?.contentWindow) return;
4464
- iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type: "dirty-check-request" }, "*");
4465
- iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type: "history-check-request" }, "*");
4466
- }
4467
- }
4468
- )
4469
- ] })
4328
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { height: "100dvh", overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4329
+ "iframe",
4330
+ {
4331
+ ref: iframeRef,
4332
+ src: `${builderBasePath.replace(/\/$/, "")}/${pageID}`,
4333
+ style: { border: "none", height: "100%", width: "100%" },
4334
+ title: "Page Builder"
4335
+ }
4336
+ ) })
4470
4337
  ] }) });
4471
4338
  }
4472
4339
 
4473
- // src/admin/components/studio/AdminStudioNewPageView.tsx
4474
- var import_react19 = require("react");
4475
- var import_ui7 = require("@payloadcms/ui");
4340
+ // src/admin/components/studio/AdminStudioPagesListView.tsx
4476
4341
  var import_jsx_runtime25 = require("react/jsx-runtime");
4477
- var pageTemplates = ["standard", "landing", "services", "contact"];
4342
+ var hasAdminAccess = (user) => {
4343
+ if (!user || typeof user !== "object") return false;
4344
+ const role = user.role;
4345
+ return typeof role === "string" && (role === "admin" || role === "developer");
4346
+ };
4478
4347
  var getPropString5 = (props, key, fallback) => {
4479
4348
  if (!props || typeof props !== "object") return fallback;
4480
4349
  const direct = props[key];
@@ -4486,107 +4355,98 @@ var getPropString5 = (props, key, fallback) => {
4486
4355
  }
4487
4356
  return fallback;
4488
4357
  };
4489
- var canManagePages = (user) => {
4490
- if (!user || typeof user !== "object") return false;
4491
- const role = user.role;
4492
- return role === "admin" || role === "editor";
4493
- };
4494
- var slugify = (value) => value.toLowerCase().trim().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-");
4495
- function AdminStudioNewPageView(props) {
4496
- const { user } = (0, import_ui7.useAuth)();
4358
+ function AdminStudioPagesListView(props) {
4497
4359
  const adminBasePath = useAdminBasePath();
4360
+ const pathname = (0, import_navigation3.usePathname)();
4361
+ const pagesPath = resolveAdminPath(adminBasePath, "/pages");
4362
+ const nestedPagePath = pathname && pathname.startsWith(`${pagesPath}/`) ? pathname.slice(`${pagesPath}/`.length).split("/")[0] : "";
4363
+ if (nestedPagePath === "new") {
4364
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(AdminStudioNewPageView, { ...props });
4365
+ }
4366
+ if (nestedPagePath) {
4367
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(AdminStudioPageEditView, { ...props });
4368
+ }
4369
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(AdminStudioPagesIndexView, { ...props, adminBasePath });
4370
+ }
4371
+ function AdminStudioPagesIndexView({
4372
+ adminBasePath,
4373
+ ...props
4374
+ }) {
4375
+ const { user } = (0, import_ui7.useAuth)();
4498
4376
  const pagesCollectionSlug = getPropString5(props, "pagesCollectionSlug", "pages");
4499
- const [submitting, setSubmitting] = (0, import_react19.useState)(false);
4377
+ const newPagePath = resolveAdminPath(adminBasePath, "/pages/new");
4378
+ const [loading, setLoading] = (0, import_react19.useState)(true);
4500
4379
  const [error, setError] = (0, import_react19.useState)(null);
4501
- if (!canManagePages(user)) {
4502
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4503
- AdminPage,
4504
- {
4505
- breadcrumbs: [
4506
- { label: "Dashboard", href: adminBasePath },
4507
- { label: "Pages", href: resolveAdminPath(adminBasePath, "/pages") },
4508
- { label: "New Page" }
4509
- ],
4510
- description: "You do not have access to create pages.",
4511
- title: "New Page",
4512
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "orion-admin-card", children: [
4513
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("strong", { children: "Access denied" }),
4514
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: "This section is restricted to administrator and editor accounts." })
4515
- ] })
4516
- }
4517
- ) });
4518
- }
4519
- const createPage = async (event) => {
4520
- event.preventDefault();
4521
- setSubmitting(true);
4522
- setError(null);
4523
- try {
4524
- const formData = new FormData(event.currentTarget);
4525
- const titleValue = String(formData.get("title") || "").trim();
4526
- const slugValue = String(formData.get("slug") || "").trim();
4527
- const templateValue = String(formData.get("template") || "standard").trim();
4528
- const template = pageTemplates.includes(templateValue) ? templateValue : "standard";
4529
- const title = titleValue || "Untitled Page";
4530
- const slug = slugValue || slugify(title) || "untitled-page";
4531
- const response = await fetch(`/api/${pagesCollectionSlug}`, {
4532
- body: JSON.stringify({
4533
- _status: "draft",
4534
- slug,
4535
- template,
4536
- title
4537
- }),
4538
- credentials: "include",
4539
- headers: {
4540
- "Content-Type": "application/json"
4541
- },
4542
- method: "POST"
4543
- });
4544
- if (!response.ok) {
4545
- throw new Error(`Failed to create page (${response.status}).`);
4546
- }
4547
- const payload = await response.json();
4548
- const id = typeof payload.id === "string" || typeof payload.id === "number" ? String(payload.id) : "";
4549
- if (!id) {
4550
- throw new Error("Page created but no document ID was returned.");
4380
+ const [docs, setDocs] = (0, import_react19.useState)([]);
4381
+ const apiURL = (0, import_react19.useMemo)(() => {
4382
+ const params = new URLSearchParams({
4383
+ depth: "0",
4384
+ limit: "100",
4385
+ sort: "-updatedAt",
4386
+ draft: "true"
4387
+ });
4388
+ return `/api/${pagesCollectionSlug}?${params.toString()}`;
4389
+ }, [pagesCollectionSlug]);
4390
+ (0, import_react19.useEffect)(() => {
4391
+ let cancelled = false;
4392
+ const run = async () => {
4393
+ setLoading(true);
4394
+ setError(null);
4395
+ try {
4396
+ const res = await fetch(apiURL, { credentials: "include" });
4397
+ if (!res.ok) {
4398
+ const body = await res.text();
4399
+ throw new Error(body || "Failed to fetch pages");
4400
+ }
4401
+ const data = await res.json();
4402
+ if (!cancelled) {
4403
+ setDocs(Array.isArray(data.docs) ? data.docs : []);
4404
+ }
4405
+ } catch (err) {
4406
+ if (!cancelled) {
4407
+ setError(err instanceof Error ? err.message : "Failed to fetch pages");
4408
+ }
4409
+ } finally {
4410
+ if (!cancelled) {
4411
+ setLoading(false);
4412
+ }
4551
4413
  }
4552
- window.location.assign(resolveAdminPath(adminBasePath, `/pages/${id}`));
4553
- } catch (createError) {
4554
- setError(createError instanceof Error ? createError.message : "Failed to create page.");
4555
- } finally {
4556
- setSubmitting(false);
4557
- }
4558
- };
4559
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4414
+ };
4415
+ void run();
4416
+ return () => {
4417
+ cancelled = true;
4418
+ };
4419
+ }, [apiURL]);
4420
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
4560
4421
  AdminPage,
4561
4422
  {
4423
+ actions: hasAdminAccess(user) ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_link2.default, { className: "orion-admin-action-button", href: newPagePath, children: "New Page" }) : null,
4562
4424
  breadcrumbs: [
4563
4425
  { label: "Dashboard", href: adminBasePath },
4564
- { label: "Pages", href: resolveAdminPath(adminBasePath, "/pages") },
4565
- { label: "New Page" }
4426
+ { label: "Pages" }
4566
4427
  ],
4567
- description: "Create a new page and open it in the custom editor.",
4568
- title: "New Page",
4569
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("form", { className: "orion-admin-form", onSubmit: createPage, children: [
4428
+ description: "Open a page to edit it in the inline custom builder.",
4429
+ title: "Pages",
4430
+ children: [
4431
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "orion-admin-list-meta", children: "Loading..." }) : null,
4570
4432
  error ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "orion-admin-error", children: error }) : null,
4571
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("label", { children: [
4572
- "Title",
4573
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("input", { name: "title", placeholder: "Services", required: true, type: "text" })
4574
- ] }),
4575
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("label", { children: [
4576
- "Slug",
4577
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("input", { name: "slug", placeholder: "services", type: "text" })
4578
- ] }),
4579
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("label", { children: [
4580
- "Template",
4581
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("select", { defaultValue: "standard", name: "template", children: [
4582
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("option", { value: "standard", children: "Standard" }),
4583
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("option", { value: "landing", children: "Landing" }),
4584
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("option", { value: "contact", children: "Contact" }),
4585
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("option", { value: "services", children: "Services" })
4586
- ] })
4587
- ] }),
4588
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("button", { disabled: submitting, type: "submit", children: submitting ? "Creating..." : "Create Page" })
4589
- ] })
4433
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "orion-admin-list", children: [
4434
+ !loading && !error && docs.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "orion-admin-card", children: [
4435
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("strong", { children: "No pages yet" }),
4436
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: "Create the first page to start building content." })
4437
+ ] }) : null,
4438
+ docs.map((doc) => {
4439
+ const id = typeof doc.id === "string" || typeof doc.id === "number" ? String(doc.id) : "";
4440
+ if (!id) return null;
4441
+ const title = typeof doc.title === "string" ? doc.title : "Untitled Page";
4442
+ const status = typeof doc._status === "string" ? doc._status : "draft";
4443
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_link2.default, { className: "orion-admin-list-item", href: resolveAdminPath(adminBasePath, `/pages/${id}`), children: [
4444
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("strong", { children: title }) }),
4445
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "orion-admin-pill", children: status })
4446
+ ] }, id);
4447
+ })
4448
+ ] })
4449
+ ]
4590
4450
  }
4591
4451
  ) });
4592
4452
  }
@@ -6855,7 +6715,7 @@ function MediaListItem({
6855
6715
 
6856
6716
  // src/admin-app/components/MediaUploadForm.tsx
6857
6717
  var import_react27 = require("react");
6858
- var import_navigation3 = require("next/navigation");
6718
+ var import_navigation4 = require("next/navigation");
6859
6719
 
6860
6720
  // src/shared/clientImageUploadOptimization.ts
6861
6721
  var MAX_DIRECT_UPLOAD_BYTES = 4e6;
@@ -6990,7 +6850,7 @@ var parseUploadError = async (response) => {
6990
6850
  return fallback;
6991
6851
  };
6992
6852
  function MediaUploadForm() {
6993
- const router = (0, import_navigation3.useRouter)();
6853
+ const router = (0, import_navigation4.useRouter)();
6994
6854
  const fileInputRef = (0, import_react27.useRef)(null);
6995
6855
  const [alt, setAlt] = (0, import_react27.useState)("");
6996
6856
  const [file, setFile] = (0, import_react27.useState)(null);
@@ -7525,17 +7385,17 @@ var FORM_TONE_OVERRIDES = {
7525
7385
  var IDENTITY_KEYS = /* @__PURE__ */ new Set(["contactEmail", "email", "firstName", "lastName", "name"]);
7526
7386
  var RESPONSE_FIELD_PREVIEW_LIMIT = 3;
7527
7387
  var RESPONSE_SCROLL_THRESHOLD = 3;
7528
- var isAdmin3 = (user) => {
7388
+ var hasAdminAccess2 = (user) => {
7529
7389
  if (!user || typeof user !== "object") return false;
7530
7390
  const role = user.role;
7531
- return typeof role === "string" && role === "admin";
7391
+ return typeof role === "string" && (role === "admin" || role === "developer");
7532
7392
  };
7533
- var isEditor2 = (user) => {
7393
+ var isEditor = (user) => {
7534
7394
  if (!user || typeof user !== "object") return false;
7535
7395
  const role = user.role;
7536
7396
  return typeof role === "string" && role === "editor";
7537
7397
  };
7538
- var canReviewForms2 = (user) => isAdmin3(user) || isEditor2(user);
7398
+ var canReviewForms2 = (user) => hasAdminAccess2(user) || isEditor(user);
7539
7399
  var getPropString13 = (props, key, fallback) => {
7540
7400
  if (!props || typeof props !== "object") return fallback;
7541
7401
  const direct = props[key];
@@ -7708,14 +7568,10 @@ function AdminStudioFormsView(props) {
7708
7568
  "formSubmissionsCollectionSlug",
7709
7569
  "form-submissions"
7710
7570
  );
7711
- const formUploadsCollectionSlug = getPropString13(props, "formUploadsCollectionSlug", "form-uploads");
7712
7571
  const adminBasePath = useAdminBasePath();
7713
- const rawFormsPath = resolveAdminPath(adminBasePath, `/collections/${formsCollectionSlug}`);
7714
- const rawSubmissionsPath = resolveAdminPath(
7715
- adminBasePath,
7716
- `/collections/${formSubmissionsCollectionSlug}`
7717
- );
7718
- const rawUploadsPath = resolveAdminPath(adminBasePath, `/collections/${formUploadsCollectionSlug}`);
7572
+ const studioFormsPath = resolveAdminPath(adminBasePath, "/forms");
7573
+ const studioSubmissionsPath = resolveAdminPath(adminBasePath, "/forms/submissions");
7574
+ const studioUploadsPath = resolveAdminPath(adminBasePath, "/forms/uploads");
7719
7575
  const [forms, setForms] = (0, import_react31.useState)([]);
7720
7576
  const [submissions, setSubmissions] = (0, import_react31.useState)([]);
7721
7577
  const [loading, setLoading] = (0, import_react31.useState)(true);
@@ -7875,7 +7731,7 @@ function AdminStudioFormsView(props) {
7875
7731
  import_link3.default,
7876
7732
  {
7877
7733
  className: "orion-admin-action-button orion-admin-action-button--soft",
7878
- href: `${rawFormsPath}/${id}`,
7734
+ href: `${studioFormsPath}/${id}`,
7879
7735
  children: "Open Form"
7880
7736
  }
7881
7737
  )
@@ -7977,7 +7833,7 @@ function AdminStudioFormsView(props) {
7977
7833
  import_link3.default,
7978
7834
  {
7979
7835
  className: "orion-admin-upload-chip",
7980
- href: `${rawUploadsPath}/${uploadID}`,
7836
+ href: `${studioUploadsPath}/${uploadID}`,
7981
7837
  children: uploadLabel
7982
7838
  },
7983
7839
  uploadID
@@ -7994,7 +7850,7 @@ function AdminStudioFormsView(props) {
7994
7850
  import_link3.default,
7995
7851
  {
7996
7852
  className: "orion-admin-action-button orion-admin-action-button--ghost",
7997
- href: `${rawSubmissionsPath}/${submissionID}`,
7853
+ href: `${studioSubmissionsPath}/${submissionID}`,
7998
7854
  children: "Open"
7999
7855
  }
8000
7856
  )
@@ -8014,50 +7870,1676 @@ function AdminStudioFormsView(props) {
8014
7870
  ) });
8015
7871
  }
8016
7872
 
8017
- // src/admin/components/studio/AdminStudioToolsView.tsx
7873
+ // src/admin/components/studio/AdminStudioFormDetailView.tsx
7874
+ var import_link4 = __toESM(require("next/link"));
8018
7875
  var import_react32 = require("react");
8019
- var import_ui12 = require("@payloadcms/ui");
8020
- var import_jsx_runtime41 = require("react/jsx-runtime");
8021
- var userRoles = ["admin", "client", "editor"];
8022
- var isAdmin4 = (user) => {
8023
- if (!user || typeof user !== "object") return false;
8024
- const role = user.role;
8025
- return typeof role === "string" && role === "admin";
7876
+
7877
+ // src/admin/components/studio/formsStudioShared.ts
7878
+ var FORM_TONES2 = [
7879
+ {
7880
+ accent: "var(--orion-cms-tone-1, var(--orion-cms-accent, var(--orion-admin-accent)))",
7881
+ accentBorder: "color-mix(in srgb, var(--orion-cms-tone-1, var(--orion-cms-accent, var(--orion-admin-accent))) 24%, transparent)",
7882
+ accentMist: "color-mix(in srgb, var(--orion-cms-tone-1, var(--orion-cms-accent, var(--orion-admin-accent))) 12%, transparent)",
7883
+ accentSoft: "color-mix(in srgb, var(--orion-cms-tone-1, var(--orion-cms-accent, var(--orion-admin-accent))) 7%, transparent)"
7884
+ },
7885
+ {
7886
+ accent: "var(--orion-cms-tone-2, var(--brand-secondary, var(--orion-admin-accent)))",
7887
+ accentBorder: "color-mix(in srgb, var(--orion-cms-tone-2, var(--brand-secondary, var(--orion-admin-accent))) 24%, transparent)",
7888
+ accentMist: "color-mix(in srgb, var(--orion-cms-tone-2, var(--brand-secondary, var(--orion-admin-accent))) 13%, transparent)",
7889
+ accentSoft: "color-mix(in srgb, var(--orion-cms-tone-2, var(--brand-secondary, var(--orion-admin-accent))) 8%, transparent)"
7890
+ },
7891
+ {
7892
+ accent: "var(--orion-cms-tone-3, color-mix(in srgb, var(--orion-cms-accent, var(--orion-admin-accent)) 72%, #5f816b))",
7893
+ 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)",
7894
+ 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)",
7895
+ 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)"
7896
+ },
7897
+ {
7898
+ accent: "var(--orion-cms-tone-4, color-mix(in srgb, var(--brand-secondary, var(--orion-admin-accent)) 72%, #7a652e))",
7899
+ 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)",
7900
+ 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)",
7901
+ 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)"
7902
+ },
7903
+ {
7904
+ accent: "var(--orion-cms-tone-5, color-mix(in srgb, var(--brand-secondary, var(--orion-admin-accent)) 68%, #8d4a40))",
7905
+ 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)",
7906
+ 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)",
7907
+ 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)"
7908
+ }
7909
+ ];
7910
+ var FORM_TONE_OVERRIDES2 = {
7911
+ "basket-request": FORM_TONES2[1],
7912
+ contact: FORM_TONES2[2],
7913
+ "vendor-inquiry": FORM_TONES2[0]
8026
7914
  };
8027
- var normalizeRole = (value) => userRoles.includes(value) ? value : "editor";
8028
- function AdminStudioToolsView(props) {
8029
- const { user } = (0, import_ui12.useAuth)();
8030
- const adminBasePath = useAdminBasePath();
8031
- const [docs, setDocs] = (0, import_react32.useState)([]);
8032
- const [loading, setLoading] = (0, import_react32.useState)(true);
8033
- const [error, setError] = (0, import_react32.useState)(null);
8034
- const [savedMessage, setSavedMessage] = (0, import_react32.useState)(null);
8035
- const [createSubmitting, setCreateSubmitting] = (0, import_react32.useState)(false);
8036
- const [updatingUserID, setUpdatingUserID] = (0, import_react32.useState)(null);
8037
- if (!isAdmin4(user)) {
8038
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8039
- AdminPage,
8040
- {
8041
- breadcrumbs: [
8042
- { label: "Dashboard", href: adminBasePath },
8043
- { label: "Admin Tools" }
8044
- ],
8045
- description: "You do not have access to this section.",
8046
- title: "Admin Tools",
8047
- children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-card", children: [
8048
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "Access denied" }),
8049
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "This section is restricted to administrator accounts." })
8050
- ] })
8051
- }
8052
- ) });
7915
+ var IDENTITY_KEYS2 = /* @__PURE__ */ new Set(["contactEmail", "email", "firstName", "lastName", "name"]);
7916
+ var RESPONSE_FIELD_PREVIEW_LIMIT2 = 3;
7917
+ var getPropString14 = (props, key, fallback) => {
7918
+ if (!props || typeof props !== "object") return fallback;
7919
+ const direct = props[key];
7920
+ if (typeof direct === "string" && direct.length > 0) return direct;
7921
+ const clientProps = props.clientProps;
7922
+ if (clientProps && typeof clientProps === "object") {
7923
+ const nested = clientProps[key];
7924
+ if (typeof nested === "string" && nested.length > 0) return nested;
8053
7925
  }
8054
- const loadUsers = async () => {
8055
- setLoading(true);
8056
- setError(null);
8057
- try {
8058
- const params = new URLSearchParams({
8059
- depth: "0",
8060
- draft: "true",
7926
+ return fallback;
7927
+ };
7928
+ var getParam3 = (params, key) => {
7929
+ if (!params || typeof params !== "object") return null;
7930
+ const value = params[key];
7931
+ if (typeof value === "string") return value;
7932
+ if (Array.isArray(value) && typeof value[0] === "string") return value[0];
7933
+ return null;
7934
+ };
7935
+ var getIDFromPathname = (pathname, marker) => {
7936
+ const markerIndex = pathname.indexOf(marker);
7937
+ if (markerIndex < 0) return null;
7938
+ const id = pathname.slice(markerIndex + marker.length).split("/")[0];
7939
+ return id ? decodeURIComponent(id) : null;
7940
+ };
7941
+ var formatDate2 = (value) => {
7942
+ if (typeof value !== "string" || value.length === 0) return "Unknown date";
7943
+ const date = new Date(value);
7944
+ if (Number.isNaN(date.getTime())) return value;
7945
+ return date.toLocaleString();
7946
+ };
7947
+ var formatFileSize4 = (value) => {
7948
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return null;
7949
+ if (value < 1024) return `${value} B`;
7950
+ if (value < 1024 * 1024) return `${(value / 1024).toFixed(1)} KB`;
7951
+ return `${(value / (1024 * 1024)).toFixed(1)} MB`;
7952
+ };
7953
+ var getFieldCount2 = (form) => Array.isArray(form.steps) ? form.steps.reduce((count, step) => {
7954
+ if (!step || typeof step !== "object") return count;
7955
+ const fields = step.fields;
7956
+ return count + (Array.isArray(fields) ? fields.length : 0);
7957
+ }, 0) : 0;
7958
+ var getFormID3 = (value) => {
7959
+ if (typeof value === "string" || typeof value === "number") return String(value);
7960
+ if (value && typeof value === "object") {
7961
+ const id = value.id;
7962
+ if (typeof id === "string" || typeof id === "number") return String(id);
7963
+ }
7964
+ return "";
7965
+ };
7966
+ var getUploads2 = (value) => Array.isArray(value) ? value.map((entry) => {
7967
+ if (typeof entry === "string" || typeof entry === "number") {
7968
+ return { id: entry };
7969
+ }
7970
+ return entry && typeof entry === "object" ? entry : null;
7971
+ }).filter((entry) => Boolean(entry)) : [];
7972
+ var getNameAndEmail2 = (data) => {
7973
+ if (!data || typeof data !== "object") return {};
7974
+ const record = data;
7975
+ const email = typeof record.email === "string" ? record.email : typeof record.contactEmail === "string" ? record.contactEmail : void 0;
7976
+ const firstName = typeof record.firstName === "string" ? record.firstName : void 0;
7977
+ const lastName = typeof record.lastName === "string" ? record.lastName : void 0;
7978
+ const fallbackName = typeof record.name === "string" ? record.name : void 0;
7979
+ const joinedName = [firstName, lastName].filter(Boolean).join(" ").trim();
7980
+ return {
7981
+ ...email ? { email } : {},
7982
+ ...joinedName ? { name: joinedName } : fallbackName ? { name: fallbackName } : {}
7983
+ };
7984
+ };
7985
+ var humanizeKey2 = (value) => value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim().replace(/^./, (char) => char.toUpperCase());
7986
+ var buildFieldLabelMap2 = (form) => {
7987
+ const labels = /* @__PURE__ */ new Map();
7988
+ for (const step of Array.isArray(form.steps) ? form.steps : []) {
7989
+ const fields = step && typeof step === "object" ? step.fields : null;
7990
+ for (const field of Array.isArray(fields) ? fields : []) {
7991
+ const name = field && typeof field === "object" && typeof field.name === "string" ? field.name.trim() : "";
7992
+ const label = field && typeof field === "object" && typeof field.label === "string" ? field.label.trim() : "";
7993
+ if (name) {
7994
+ labels.set(name, label || humanizeKey2(name));
7995
+ }
7996
+ }
7997
+ }
7998
+ return labels;
7999
+ };
8000
+ var truncateText2 = (value, maxLength = 64) => {
8001
+ const normalized = value.replace(/\s+/g, " ").trim();
8002
+ if (normalized.length <= maxLength) return normalized;
8003
+ return `${normalized.slice(0, maxLength - 1).trimEnd()}...`;
8004
+ };
8005
+ var formatPreviewValue2 = (value) => {
8006
+ if (value === null || value === void 0) return null;
8007
+ if (typeof value === "boolean") return value ? "Yes" : "No";
8008
+ if (typeof value === "number") return String(value);
8009
+ if (typeof value === "string") {
8010
+ const trimmed = value.trim();
8011
+ return trimmed ? truncateText2(trimmed, 72) : null;
8012
+ }
8013
+ if (Array.isArray(value)) {
8014
+ const joined = value.map((entry) => String(entry).trim()).filter(Boolean).join(", ");
8015
+ return joined ? truncateText2(joined, 72) : null;
8016
+ }
8017
+ if (typeof value === "object") {
8018
+ return truncateText2(JSON.stringify(value), 72);
8019
+ }
8020
+ return truncateText2(String(value), 72);
8021
+ };
8022
+ var getPreviewFields2 = (data, fieldLabels) => {
8023
+ if (!data || typeof data !== "object") return [];
8024
+ return Object.entries(data).filter(([key]) => !IDENTITY_KEYS2.has(key)).map(([key, value]) => {
8025
+ const formatted = formatPreviewValue2(value);
8026
+ if (!formatted) return null;
8027
+ return {
8028
+ label: fieldLabels.get(key) || humanizeKey2(key),
8029
+ value: formatted
8030
+ };
8031
+ }).filter((entry) => Boolean(entry)).slice(0, RESPONSE_FIELD_PREVIEW_LIMIT2);
8032
+ };
8033
+ var getInitials3 = (...values) => {
8034
+ const source = values.find((value) => typeof value === "string" && value.trim().length > 0);
8035
+ if (!source) return "FM";
8036
+ const cleaned = source.replace(/[^a-z0-9]+/gi, " ").trim();
8037
+ if (!cleaned) return "FM";
8038
+ const parts = cleaned.split(/\s+/).filter(Boolean);
8039
+ if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
8040
+ return `${parts[0][0] || ""}${parts[1][0] || ""}`.toUpperCase();
8041
+ };
8042
+ var getHash2 = (value) => {
8043
+ let hash = 0;
8044
+ for (let index = 0; index < value.length; index += 1) {
8045
+ hash = hash * 31 + value.charCodeAt(index) >>> 0;
8046
+ }
8047
+ return hash;
8048
+ };
8049
+ var normalizeToneKey2 = (value) => value?.trim().toLowerCase() || "";
8050
+ var getFormTone2 = (slug, fallbackSeed) => {
8051
+ const normalizedSlug = normalizeToneKey2(slug);
8052
+ if (normalizedSlug && FORM_TONE_OVERRIDES2[normalizedSlug]) {
8053
+ return FORM_TONE_OVERRIDES2[normalizedSlug];
8054
+ }
8055
+ const normalizedSeed = normalizeToneKey2(fallbackSeed);
8056
+ if (normalizedSeed && FORM_TONE_OVERRIDES2[normalizedSeed]) {
8057
+ return FORM_TONE_OVERRIDES2[normalizedSeed];
8058
+ }
8059
+ return FORM_TONES2[getHash2(slug || fallbackSeed) % FORM_TONES2.length];
8060
+ };
8061
+ var getFormToneStyle2 = (slug, fallbackSeed) => {
8062
+ const tone = getFormTone2(slug, fallbackSeed);
8063
+ return {
8064
+ ["--form-accent"]: tone.accent,
8065
+ ["--form-accent-border"]: tone.accentBorder,
8066
+ ["--form-accent-mist"]: tone.accentMist,
8067
+ ["--form-accent-soft"]: tone.accentSoft
8068
+ };
8069
+ };
8070
+ var getFormTitle2 = (value) => {
8071
+ if (value && typeof value === "object" && typeof value.title === "string") {
8072
+ const title = value.title.trim();
8073
+ if (title.length > 0) return title;
8074
+ }
8075
+ if (typeof value === "string" && value.trim().length > 0) {
8076
+ return value;
8077
+ }
8078
+ return "Untitled Form";
8079
+ };
8080
+
8081
+ // src/admin/components/studio/AdminStudioFormDetailView.tsx
8082
+ var import_jsx_runtime41 = require("react/jsx-runtime");
8083
+ var getNonEmptyText = (value, fallback = "") => typeof value === "string" && value.trim().length > 0 ? value : fallback;
8084
+ var normalizeSteps = (value) => {
8085
+ if (!Array.isArray(value)) {
8086
+ return [];
8087
+ }
8088
+ return value.map((step) => step && typeof step === "object" && !Array.isArray(step) ? step : {});
8089
+ };
8090
+ var normalizeFormResponse = (value) => {
8091
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
8092
+ return {};
8093
+ }
8094
+ const record = value;
8095
+ const nestedDoc = record.doc;
8096
+ if (nestedDoc && typeof nestedDoc === "object" && !Array.isArray(nestedDoc)) {
8097
+ return nestedDoc;
8098
+ }
8099
+ return record;
8100
+ };
8101
+ var toEditorState = (doc) => {
8102
+ const emails = doc.emails && typeof doc.emails === "object" ? doc.emails : null;
8103
+ const adminRecipients = Array.isArray(emails?.adminRecipients) ? emails?.adminRecipients.map(
8104
+ (entry) => entry && typeof entry === "object" && typeof entry.email === "string" ? entry.email.trim() : ""
8105
+ ).filter(Boolean) : [];
8106
+ return {
8107
+ adminRecipientsText: adminRecipients.join("\n"),
8108
+ adminSubject: getNonEmptyText(emails?.adminSubject),
8109
+ confirmationHeading: getNonEmptyText(emails?.confirmationHeading),
8110
+ confirmationMessage: getNonEmptyText(emails?.confirmationMessage),
8111
+ confirmationSubject: getNonEmptyText(emails?.confirmationSubject),
8112
+ sendAdmin: emails?.sendAdmin !== false,
8113
+ sendConfirmation: emails?.sendConfirmation !== false,
8114
+ slug: getNonEmptyText(doc.slug),
8115
+ steps: normalizeSteps(doc.steps),
8116
+ submitLabel: getNonEmptyText(doc.submitLabel, "Submit"),
8117
+ successMessage: getNonEmptyText(doc.successMessage),
8118
+ title: getNonEmptyText(doc.title, "Untitled Form")
8119
+ };
8120
+ };
8121
+ var checkboxLabelStyle = {
8122
+ alignItems: "center",
8123
+ display: "flex",
8124
+ gap: "0.6rem"
8125
+ };
8126
+ var sectionGridStyle = {
8127
+ display: "grid",
8128
+ gap: "1rem",
8129
+ gridTemplateColumns: "repeat(auto-fit, minmax(320px, 1fr))"
8130
+ };
8131
+ var fieldTypeOptions = [
8132
+ "text",
8133
+ "textarea",
8134
+ "email",
8135
+ "phone",
8136
+ "url",
8137
+ "select",
8138
+ "radio",
8139
+ "checkbox",
8140
+ "checkbox-group",
8141
+ "date",
8142
+ "file"
8143
+ ];
8144
+ var getFields = (step) => Array.isArray(step.fields) ? step.fields.map(
8145
+ (field) => field && typeof field === "object" && !Array.isArray(field) ? field : {}
8146
+ ) : [];
8147
+ var toOptionsText = (value) => Array.isArray(value) ? value.map((entry) => {
8148
+ if (entry && typeof entry === "object" && !Array.isArray(entry)) {
8149
+ const record = entry;
8150
+ const label = typeof record.label === "string" ? record.label : "";
8151
+ const optionValue = typeof record.value === "string" ? record.value : label;
8152
+ return label && optionValue && label !== optionValue ? `${label} | ${optionValue}` : label || optionValue;
8153
+ }
8154
+ return typeof entry === "string" ? entry : "";
8155
+ }).filter(Boolean).join("\n") : "";
8156
+ var fromOptionsText = (value) => value.split("\n").map((entry) => entry.trim()).filter(Boolean).map((entry) => {
8157
+ const [label, optionValue] = entry.split("|").map((part) => part.trim());
8158
+ return {
8159
+ label,
8160
+ value: optionValue || label
8161
+ };
8162
+ });
8163
+ var slugifyFieldName = (value) => value.trim().replace(/[^a-z0-9]+/gi, " ").trim().replace(/\s+([a-z0-9])/gi, (_, char) => char.toUpperCase()).replace(/^./, (char) => char.toLowerCase());
8164
+ var blankField = () => ({
8165
+ label: "New field",
8166
+ name: "newField",
8167
+ required: false,
8168
+ type: "text"
8169
+ });
8170
+ var blankStep = () => ({
8171
+ fields: [blankField()],
8172
+ title: "New step"
8173
+ });
8174
+ var getStepTitle = (step, stepIndex) => getNonEmptyText(step.title, `Step ${stepIndex + 1}`);
8175
+ var getFieldLabel = (field, fieldIndex) => getNonEmptyText(field.label, getNonEmptyText(field.name, `Field ${fieldIndex + 1}`));
8176
+ var formatFieldTypeLabel = (value) => getNonEmptyText(value, "text").replace(/-/g, " ").replace(/^./, (char) => char.toUpperCase());
8177
+ var getStepDestination = (stepIndex, stepCount) => {
8178
+ if (stepIndex < stepCount - 1) {
8179
+ return `Next: Step ${stepIndex + 2}`;
8180
+ }
8181
+ return "Then: Submit form";
8182
+ };
8183
+ var moveItem = (items, fromIndex, toIndex) => {
8184
+ if (toIndex < 0 || toIndex >= items.length) {
8185
+ return items;
8186
+ }
8187
+ const nextItems = [...items];
8188
+ const [item] = nextItems.splice(fromIndex, 1);
8189
+ nextItems.splice(toIndex, 0, item);
8190
+ return nextItems;
8191
+ };
8192
+ function getFormIDFromPathname(pathname) {
8193
+ const marker = "/forms/";
8194
+ const raw = getIDFromPathname(pathname, marker);
8195
+ if (!raw || raw === "submissions" || raw === "uploads") {
8196
+ return null;
8197
+ }
8198
+ return raw;
8199
+ }
8200
+ function AdminStudioFormDetailView(props) {
8201
+ const formsCollectionSlug = getPropString14(props, "formsCollectionSlug", "forms");
8202
+ const formSubmissionsCollectionSlug = getPropString14(
8203
+ props,
8204
+ "formSubmissionsCollectionSlug",
8205
+ "form-submissions"
8206
+ );
8207
+ const adminBasePath = useAdminBasePath();
8208
+ const formsPath = resolveAdminPath(adminBasePath, "/forms");
8209
+ const formIDFromParams = (0, import_react32.useMemo)(() => getParam3(props.params, "id"), [props.params]);
8210
+ const [formID, setFormID] = (0, import_react32.useState)(formIDFromParams);
8211
+ const [didResolvePathFallback, setDidResolvePathFallback] = (0, import_react32.useState)(false);
8212
+ const [doc, setDoc] = (0, import_react32.useState)(null);
8213
+ const [submissions, setSubmissions] = (0, import_react32.useState)([]);
8214
+ const [editorState, setEditorState] = (0, import_react32.useState)(null);
8215
+ const [loading, setLoading] = (0, import_react32.useState)(true);
8216
+ const [error, setError] = (0, import_react32.useState)(null);
8217
+ const [saving, setSaving] = (0, import_react32.useState)(false);
8218
+ const [savedMessage, setSavedMessage] = (0, import_react32.useState)(null);
8219
+ (0, import_react32.useEffect)(() => {
8220
+ if (formIDFromParams) {
8221
+ setFormID(formIDFromParams);
8222
+ setDidResolvePathFallback(true);
8223
+ return;
8224
+ }
8225
+ if (typeof window !== "undefined") {
8226
+ setFormID(getFormIDFromPathname(window.location.pathname));
8227
+ }
8228
+ setDidResolvePathFallback(true);
8229
+ }, [formIDFromParams]);
8230
+ const loadDoc = async (id) => {
8231
+ setLoading(true);
8232
+ setError(null);
8233
+ try {
8234
+ const submissionsParams = new URLSearchParams({
8235
+ depth: "1",
8236
+ limit: "25",
8237
+ sort: "-submittedAt"
8238
+ });
8239
+ submissionsParams.set("where[form][equals]", id);
8240
+ const [formResponse, submissionsResponse] = await Promise.all([
8241
+ fetch(`/api/${formsCollectionSlug}/${encodeURIComponent(id)}?depth=0&draft=true`, {
8242
+ credentials: "include"
8243
+ }),
8244
+ fetch(`/api/${formSubmissionsCollectionSlug}?${submissionsParams.toString()}`, {
8245
+ credentials: "include"
8246
+ })
8247
+ ]);
8248
+ if (!formResponse.ok) {
8249
+ throw new Error(`Failed to load form (${formResponse.status}).`);
8250
+ }
8251
+ if (!submissionsResponse.ok) {
8252
+ throw new Error(`Failed to load submissions (${submissionsResponse.status}).`);
8253
+ }
8254
+ const nextDoc = normalizeFormResponse(await formResponse.json());
8255
+ const submissionsPayload = await submissionsResponse.json();
8256
+ const nextSubmissions = Array.isArray(submissionsPayload.docs) ? submissionsPayload.docs : [];
8257
+ setDoc(nextDoc);
8258
+ setEditorState(toEditorState(nextDoc));
8259
+ setSubmissions(nextSubmissions);
8260
+ } catch (loadError) {
8261
+ setError(loadError instanceof Error ? loadError.message : "Failed to load form.");
8262
+ setDoc(null);
8263
+ setEditorState(null);
8264
+ setSubmissions([]);
8265
+ } finally {
8266
+ setLoading(false);
8267
+ }
8268
+ };
8269
+ (0, import_react32.useEffect)(() => {
8270
+ if (!formID) {
8271
+ return;
8272
+ }
8273
+ void loadDoc(formID);
8274
+ }, [formID, formsCollectionSlug, formSubmissionsCollectionSlug]);
8275
+ const save = async (event) => {
8276
+ event.preventDefault();
8277
+ if (!formID || !editorState) {
8278
+ return;
8279
+ }
8280
+ setSaving(true);
8281
+ setError(null);
8282
+ setSavedMessage(null);
8283
+ try {
8284
+ const payload = {
8285
+ emails: {
8286
+ adminRecipients: editorState.adminRecipientsText.split("\n").map((value) => value.trim()).filter(Boolean).map((email) => ({ email })),
8287
+ adminSubject: editorState.adminSubject.trim(),
8288
+ confirmationHeading: editorState.confirmationHeading.trim(),
8289
+ confirmationMessage: editorState.confirmationMessage,
8290
+ confirmationSubject: editorState.confirmationSubject.trim(),
8291
+ sendAdmin: editorState.sendAdmin,
8292
+ sendConfirmation: editorState.sendConfirmation
8293
+ },
8294
+ slug: editorState.slug.trim(),
8295
+ steps: editorState.steps,
8296
+ submitLabel: editorState.submitLabel.trim(),
8297
+ successMessage: editorState.successMessage,
8298
+ title: editorState.title.trim()
8299
+ };
8300
+ const response = await fetch(`/api/${formsCollectionSlug}/${encodeURIComponent(formID)}`, {
8301
+ body: JSON.stringify(payload),
8302
+ credentials: "include",
8303
+ headers: {
8304
+ "Content-Type": "application/json"
8305
+ },
8306
+ method: "PATCH"
8307
+ });
8308
+ if (!response.ok) {
8309
+ throw new Error(`Failed to save form (${response.status}).`);
8310
+ }
8311
+ const nextDoc = normalizeFormResponse(await response.json());
8312
+ setDoc(nextDoc);
8313
+ setEditorState(toEditorState(nextDoc));
8314
+ setSavedMessage("Saved.");
8315
+ } catch (saveError) {
8316
+ setError(saveError instanceof Error ? saveError.message : "Failed to save form.");
8317
+ } finally {
8318
+ setSaving(false);
8319
+ }
8320
+ };
8321
+ if (!formID && !didResolvePathFallback) {
8322
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8323
+ AdminPage,
8324
+ {
8325
+ breadcrumbs: [
8326
+ { label: "Dashboard", href: adminBasePath },
8327
+ { label: "Forms", href: formsPath },
8328
+ { label: "Form" }
8329
+ ],
8330
+ description: "Loading form workspace...",
8331
+ title: "Form",
8332
+ children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_jsx_runtime41.Fragment, {})
8333
+ }
8334
+ ) });
8335
+ }
8336
+ const title = doc && typeof doc.title === "string" && doc.title.trim().length > 0 ? doc.title : "Form";
8337
+ const slug = doc && typeof doc.slug === "string" ? doc.slug : "";
8338
+ const toneStyle = getFormToneStyle2(slug, title || formID || "form");
8339
+ const fieldLabels = doc ? buildFieldLabelMap2(doc) : /* @__PURE__ */ new Map();
8340
+ const latestSubmission = submissions[0];
8341
+ const stepCount = editorState?.steps.length || 0;
8342
+ const fieldCount = editorState ? editorState.steps.reduce((count, step) => count + getFields(step).length, 0) : doc ? getFieldCount2(doc) : 0;
8343
+ const updateStep = (stepIndex, patch) => {
8344
+ setEditorState(
8345
+ (current) => current ? {
8346
+ ...current,
8347
+ steps: current.steps.map(
8348
+ (step, index) => index === stepIndex ? { ...step, ...patch } : step
8349
+ )
8350
+ } : current
8351
+ );
8352
+ };
8353
+ const updateField = (stepIndex, fieldIndex, patch) => {
8354
+ setEditorState((current) => {
8355
+ if (!current) return current;
8356
+ return {
8357
+ ...current,
8358
+ steps: current.steps.map((step, index) => {
8359
+ if (index !== stepIndex) return step;
8360
+ const fields = getFields(step).map(
8361
+ (field, currentFieldIndex) => currentFieldIndex === fieldIndex ? { ...field, ...patch } : field
8362
+ );
8363
+ return { ...step, fields };
8364
+ })
8365
+ };
8366
+ });
8367
+ };
8368
+ const moveStep = (stepIndex, direction) => {
8369
+ setEditorState(
8370
+ (current) => current ? {
8371
+ ...current,
8372
+ steps: moveItem(current.steps, stepIndex, stepIndex + direction)
8373
+ } : current
8374
+ );
8375
+ };
8376
+ const moveField = (stepIndex, fieldIndex, direction) => {
8377
+ setEditorState((current) => {
8378
+ if (!current) return current;
8379
+ return {
8380
+ ...current,
8381
+ steps: current.steps.map(
8382
+ (step, index) => index === stepIndex ? { ...step, fields: moveItem(getFields(step), fieldIndex, fieldIndex + direction) } : step
8383
+ )
8384
+ };
8385
+ });
8386
+ };
8387
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
8388
+ AdminPage,
8389
+ {
8390
+ breadcrumbs: [
8391
+ { label: "Dashboard", href: adminBasePath },
8392
+ { label: "Forms", href: formsPath },
8393
+ { label: title }
8394
+ ],
8395
+ description: "Manage form content and review recent responses without leaving Studio.",
8396
+ title: "Form",
8397
+ children: [
8398
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-list-meta", children: "Loading..." }) : null,
8399
+ error ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-error", children: error }) : null,
8400
+ savedMessage ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-success", children: savedMessage }) : null,
8401
+ !loading && !error && doc && editorState && formID ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { style: { display: "grid", gap: "1rem" }, children: [
8402
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-forms-summary-grid", children: [
8403
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("article", { className: "orion-admin-overview-stat", children: [
8404
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-overview-stat-label", children: "Workflow steps" }),
8405
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: stepCount }),
8406
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { children: "Configured stages in the public form flow." })
8407
+ ] }),
8408
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("article", { className: "orion-admin-overview-stat", children: [
8409
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-overview-stat-label", children: "Fields" }),
8410
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: fieldCount }),
8411
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { children: "Total visible and conditional fields across every step." })
8412
+ ] }),
8413
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("article", { className: "orion-admin-overview-stat", children: [
8414
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-overview-stat-label", children: "Recent submissions" }),
8415
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: submissions.length }),
8416
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { children: latestSubmission ? `Latest response ${formatDate2(latestSubmission.submittedAt)}` : "No responses have been recorded yet." })
8417
+ ] })
8418
+ ] }),
8419
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("section", { className: "orion-admin-form-board", style: toneStyle, children: [
8420
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-form-board-header", children: [
8421
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-form-board-heading", children: [
8422
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-form-board-kicker-row", children: [
8423
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-form-board-kicker", children: slug || "No slug set" }),
8424
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-form-board-meta", children: doc.updatedAt ? `Updated ${formatDate2(doc.updatedAt)}` : "Update time unavailable" })
8425
+ ] }),
8426
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-form-board-title-row", children: [
8427
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-form-board-mark", children: getInitials3(title, slug) }),
8428
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-form-board-copy", children: [
8429
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("h2", { className: "orion-admin-form-board-title", children: title }),
8430
+ /* @__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." })
8431
+ ] })
8432
+ ] })
8433
+ ] }),
8434
+ /* @__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: [
8435
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-form-board-count-value", children: submissions.length }),
8436
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "orion-admin-form-board-count-label", children: [
8437
+ "response",
8438
+ submissions.length === 1 ? "" : "s"
8439
+ ] })
8440
+ ] }) })
8441
+ ] }),
8442
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-form-board-metrics", children: [
8443
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("article", { className: "orion-admin-form-metric", children: [
8444
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-form-metric-label", children: "Submit button" }),
8445
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { className: "orion-admin-form-metric-value is-copy", children: editorState.submitLabel || "Submit" })
8446
+ ] }),
8447
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("article", { className: "orion-admin-form-metric", children: [
8448
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-form-metric-label", children: "Admin notifications" }),
8449
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { className: "orion-admin-form-metric-value", children: editorState.sendAdmin ? "On" : "Off" })
8450
+ ] }),
8451
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("article", { className: "orion-admin-form-metric", children: [
8452
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-form-metric-label", children: "Confirmation email" }),
8453
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { className: "orion-admin-form-metric-value", children: editorState.sendConfirmation ? "On" : "Off" })
8454
+ ] }),
8455
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("article", { className: "orion-admin-form-metric", children: [
8456
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-form-metric-label", children: "Latest response" }),
8457
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { className: "orion-admin-form-metric-value is-copy", children: latestSubmission ? formatDate2(latestSubmission.submittedAt) : "No activity yet" })
8458
+ ] })
8459
+ ] })
8460
+ ] }),
8461
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { style: sectionGridStyle, children: [
8462
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { style: { display: "grid", gap: "1rem" }, children: [
8463
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-card", children: [
8464
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "Step preview" }),
8465
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "Review the public workflow as visitors will move through it." }),
8466
+ /* @__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) => {
8467
+ const fields = getFields(record);
8468
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-form", children: [
8469
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { children: [
8470
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("strong", { children: [
8471
+ "Step ",
8472
+ stepIndex + 1,
8473
+ ": ",
8474
+ getNonEmptyText(record?.title, "Untitled Step")
8475
+ ] }),
8476
+ getNonEmptyText(record?.subtitle) ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-list-meta", style: { marginTop: "0.25rem" }, children: getNonEmptyText(record?.subtitle) }) : null
8477
+ ] }),
8478
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-inline-actions", children: [
8479
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "orion-admin-pill", children: [
8480
+ fields.length,
8481
+ " field",
8482
+ fields.length === 1 ? "" : "s"
8483
+ ] }),
8484
+ record?.allowSkip === true ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-pill", children: "Can skip" }) : null,
8485
+ getNonEmptyText(record?.nextLabel) ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "orion-admin-pill", children: [
8486
+ "Next: ",
8487
+ getNonEmptyText(record?.nextLabel)
8488
+ ] }) : null
8489
+ ] }),
8490
+ fields.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-list", children: fields.map((field, fieldIndex) => {
8491
+ const fieldRecord = field && typeof field === "object" && !Array.isArray(field) ? field : null;
8492
+ const type = getNonEmptyText(fieldRecord?.type, "text");
8493
+ const label = getNonEmptyText(
8494
+ fieldRecord?.label,
8495
+ getNonEmptyText(fieldRecord?.name, `Field ${fieldIndex + 1}`)
8496
+ );
8497
+ const helpText = getNonEmptyText(fieldRecord?.helpText);
8498
+ const condition = fieldRecord?.condition && typeof fieldRecord.condition === "object" && !Array.isArray(fieldRecord.condition) ? fieldRecord.condition : null;
8499
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-list-item", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { children: [
8500
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: label }),
8501
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-list-meta", children: [
8502
+ type,
8503
+ fieldRecord?.required === true ? " \xB7 required" : "",
8504
+ condition?.field && condition?.equals ? ` \xB7 when ${String(condition.field)} = ${String(condition.equals)}` : ""
8505
+ ] }),
8506
+ helpText ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8507
+ "div",
8508
+ {
8509
+ className: "orion-admin-list-meta",
8510
+ style: { marginTop: "0.25rem" },
8511
+ children: helpText
8512
+ }
8513
+ ) : null
8514
+ ] }) }, `field-${fieldIndex}`);
8515
+ }) }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-list-meta", children: "This step has no fields." })
8516
+ ] }, `step-${stepIndex}`);
8517
+ }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-empty-state", children: [
8518
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "No steps configured" }),
8519
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "Add at least one step in Form settings to publish this form." })
8520
+ ] }) })
8521
+ ] }),
8522
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-card", children: [
8523
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "Recent submissions" }),
8524
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "Jump from the form definition into the latest responses." }),
8525
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { style: { display: "grid", gap: "0.85rem", marginTop: "1rem" }, children: submissions.length > 0 ? submissions.map((submission) => {
8526
+ const submissionID = typeof submission.id === "string" || typeof submission.id === "number" ? String(submission.id) : "";
8527
+ if (!submissionID) return null;
8528
+ const identity = getNameAndEmail2(submission.data);
8529
+ const previewFields = getPreviewFields2(submission.data, fieldLabels);
8530
+ const formSubmissionPath = resolveAdminPath(
8531
+ adminBasePath,
8532
+ `/forms/submissions/${submissionID}`
8533
+ );
8534
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_link4.default, { className: "orion-admin-list-item", href: formSubmissionPath, children: [
8535
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { children: [
8536
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: identity.name || identity.email || "Submission" }),
8537
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-list-meta", children: formatDate2(submission.submittedAt) }),
8538
+ 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
8539
+ ] }),
8540
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-action-button orion-admin-action-button--ghost", children: "Open" })
8541
+ ] }, submissionID);
8542
+ }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-empty-state", children: [
8543
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "No responses yet" }),
8544
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "This view will populate as soon as the form starts receiving traffic." })
8545
+ ] }) })
8546
+ ] })
8547
+ ] }),
8548
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("form", { className: "orion-admin-form", onSubmit: save, children: [
8549
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "Form settings" }),
8550
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8551
+ "Title",
8552
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8553
+ "input",
8554
+ {
8555
+ onChange: (event) => setEditorState(
8556
+ (current) => current ? { ...current, title: event.target.value } : current
8557
+ ),
8558
+ required: true,
8559
+ type: "text",
8560
+ value: editorState.title
8561
+ }
8562
+ )
8563
+ ] }),
8564
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8565
+ "Slug",
8566
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8567
+ "input",
8568
+ {
8569
+ onChange: (event) => setEditorState(
8570
+ (current) => current ? { ...current, slug: event.target.value } : current
8571
+ ),
8572
+ required: true,
8573
+ type: "text",
8574
+ value: editorState.slug
8575
+ }
8576
+ )
8577
+ ] }),
8578
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8579
+ "Submit button",
8580
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8581
+ "input",
8582
+ {
8583
+ onChange: (event) => setEditorState(
8584
+ (current) => current ? { ...current, submitLabel: event.target.value } : current
8585
+ ),
8586
+ type: "text",
8587
+ value: editorState.submitLabel
8588
+ }
8589
+ )
8590
+ ] }),
8591
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8592
+ "Success message",
8593
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8594
+ "textarea",
8595
+ {
8596
+ onChange: (event) => setEditorState(
8597
+ (current) => current ? { ...current, successMessage: event.target.value } : current
8598
+ ),
8599
+ rows: 4,
8600
+ value: editorState.successMessage
8601
+ }
8602
+ )
8603
+ ] }),
8604
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-card", children: [
8605
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "Email behavior" }),
8606
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { style: { display: "grid", gap: "0.85rem", marginTop: "0.9rem" }, children: [
8607
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { style: checkboxLabelStyle, children: [
8608
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8609
+ "input",
8610
+ {
8611
+ checked: editorState.sendAdmin,
8612
+ onChange: (event) => setEditorState(
8613
+ (current) => current ? { ...current, sendAdmin: event.target.checked } : current
8614
+ ),
8615
+ type: "checkbox"
8616
+ }
8617
+ ),
8618
+ "Send admin notifications"
8619
+ ] }),
8620
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8621
+ "Admin recipients",
8622
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8623
+ "textarea",
8624
+ {
8625
+ onChange: (event) => setEditorState(
8626
+ (current) => current ? { ...current, adminRecipientsText: event.target.value } : current
8627
+ ),
8628
+ placeholder: "one@email.com\ntwo@email.com",
8629
+ rows: 4,
8630
+ value: editorState.adminRecipientsText
8631
+ }
8632
+ )
8633
+ ] }),
8634
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8635
+ "Admin subject",
8636
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8637
+ "input",
8638
+ {
8639
+ onChange: (event) => setEditorState(
8640
+ (current) => current ? { ...current, adminSubject: event.target.value } : current
8641
+ ),
8642
+ type: "text",
8643
+ value: editorState.adminSubject
8644
+ }
8645
+ )
8646
+ ] }),
8647
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { style: checkboxLabelStyle, children: [
8648
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8649
+ "input",
8650
+ {
8651
+ checked: editorState.sendConfirmation,
8652
+ onChange: (event) => setEditorState(
8653
+ (current) => current ? { ...current, sendConfirmation: event.target.checked } : current
8654
+ ),
8655
+ type: "checkbox"
8656
+ }
8657
+ ),
8658
+ "Send confirmation email"
8659
+ ] }),
8660
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8661
+ "Confirmation subject",
8662
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8663
+ "input",
8664
+ {
8665
+ onChange: (event) => setEditorState(
8666
+ (current) => current ? { ...current, confirmationSubject: event.target.value } : current
8667
+ ),
8668
+ type: "text",
8669
+ value: editorState.confirmationSubject
8670
+ }
8671
+ )
8672
+ ] }),
8673
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8674
+ "Confirmation heading",
8675
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8676
+ "input",
8677
+ {
8678
+ onChange: (event) => setEditorState(
8679
+ (current) => current ? { ...current, confirmationHeading: event.target.value } : current
8680
+ ),
8681
+ type: "text",
8682
+ value: editorState.confirmationHeading
8683
+ }
8684
+ )
8685
+ ] }),
8686
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8687
+ "Confirmation message",
8688
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8689
+ "textarea",
8690
+ {
8691
+ onChange: (event) => setEditorState(
8692
+ (current) => current ? { ...current, confirmationMessage: event.target.value } : current
8693
+ ),
8694
+ rows: 4,
8695
+ value: editorState.confirmationMessage
8696
+ }
8697
+ )
8698
+ ] })
8699
+ ] })
8700
+ ] }),
8701
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-card orion-admin-workflow-editor", children: [
8702
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-workflow-editor-header", children: [
8703
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { children: [
8704
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "Form steps" }),
8705
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "Build the visitor flow, then edit each step's fields below." })
8706
+ ] }),
8707
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8708
+ "button",
8709
+ {
8710
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
8711
+ onClick: () => setEditorState(
8712
+ (current) => current ? { ...current, steps: [...current.steps, blankStep()] } : current
8713
+ ),
8714
+ type: "button",
8715
+ children: "Add step"
8716
+ }
8717
+ )
8718
+ ] }),
8719
+ editorState.steps.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-empty-state", children: [
8720
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "No steps configured" }),
8721
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "Add a first step to start building the public form flow." })
8722
+ ] }) : null,
8723
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-step-editor-list", children: editorState.steps.map((step, stepIndex) => {
8724
+ const fields = getFields(step);
8725
+ const requiredCount = fields.filter((field) => field.required === true).length;
8726
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("details", { className: "orion-admin-step-editor", open: true, children: [
8727
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("summary", { className: "orion-admin-step-editor-summary", children: [
8728
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-workflow-node-number", children: stepIndex + 1 }),
8729
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-step-editor-title", children: getStepTitle(step, stepIndex) }),
8730
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "orion-admin-step-editor-meta", children: [
8731
+ fields.length,
8732
+ " field",
8733
+ fields.length === 1 ? "" : "s",
8734
+ requiredCount > 0 ? ` \xB7 ${requiredCount} required` : ""
8735
+ ] }),
8736
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-workflow-node-destination", children: getStepDestination(stepIndex, editorState.steps.length) })
8737
+ ] }),
8738
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-step-editor-body", children: [
8739
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-step-editor-actions", children: [
8740
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8741
+ "button",
8742
+ {
8743
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
8744
+ disabled: stepIndex === 0,
8745
+ onClick: () => moveStep(stepIndex, -1),
8746
+ type: "button",
8747
+ children: "Move up"
8748
+ }
8749
+ ),
8750
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8751
+ "button",
8752
+ {
8753
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
8754
+ disabled: stepIndex === editorState.steps.length - 1,
8755
+ onClick: () => moveStep(stepIndex, 1),
8756
+ type: "button",
8757
+ children: "Move down"
8758
+ }
8759
+ ),
8760
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8761
+ "button",
8762
+ {
8763
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
8764
+ onClick: () => setEditorState(
8765
+ (current) => current ? {
8766
+ ...current,
8767
+ steps: current.steps.filter((_, index) => index !== stepIndex)
8768
+ } : current
8769
+ ),
8770
+ type: "button",
8771
+ children: "Remove step"
8772
+ }
8773
+ )
8774
+ ] }),
8775
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-step-settings-grid", children: [
8776
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8777
+ "Step title",
8778
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8779
+ "input",
8780
+ {
8781
+ onChange: (event) => updateStep(stepIndex, { title: event.target.value }),
8782
+ type: "text",
8783
+ value: getNonEmptyText(step.title)
8784
+ }
8785
+ )
8786
+ ] }),
8787
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8788
+ "Next button label",
8789
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8790
+ "input",
8791
+ {
8792
+ onChange: (event) => updateStep(stepIndex, { nextLabel: event.target.value }),
8793
+ placeholder: "Next",
8794
+ type: "text",
8795
+ value: getNonEmptyText(step.nextLabel)
8796
+ }
8797
+ )
8798
+ ] })
8799
+ ] }),
8800
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8801
+ "Step intro text",
8802
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8803
+ "textarea",
8804
+ {
8805
+ onChange: (event) => updateStep(stepIndex, { subtitle: event.target.value }),
8806
+ rows: 3,
8807
+ value: getNonEmptyText(step.subtitle)
8808
+ }
8809
+ )
8810
+ ] }),
8811
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { style: checkboxLabelStyle, children: [
8812
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8813
+ "input",
8814
+ {
8815
+ checked: step.allowSkip === true,
8816
+ onChange: (event) => updateStep(stepIndex, { allowSkip: event.target.checked }),
8817
+ type: "checkbox"
8818
+ }
8819
+ ),
8820
+ "Allow visitors to skip this step"
8821
+ ] }),
8822
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-field-list-header", children: [
8823
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { children: [
8824
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "Fields in this step" }),
8825
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "These appear together before the visitor moves to the next step." })
8826
+ ] }),
8827
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8828
+ "button",
8829
+ {
8830
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
8831
+ onClick: () => setEditorState(
8832
+ (current) => current ? {
8833
+ ...current,
8834
+ steps: current.steps.map(
8835
+ (currentStep, index) => index === stepIndex ? { ...currentStep, fields: [...getFields(currentStep), blankField()] } : currentStep
8836
+ )
8837
+ } : current
8838
+ ),
8839
+ type: "button",
8840
+ children: "Add field"
8841
+ }
8842
+ )
8843
+ ] }),
8844
+ fields.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-field-editor-list", children: fields.map((field, fieldIndex) => {
8845
+ const label = getFieldLabel(field, fieldIndex);
8846
+ const fieldType = getNonEmptyText(field.type, "text");
8847
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("details", { className: "orion-admin-field-editor", children: [
8848
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("summary", { className: "orion-admin-field-editor-summary", children: [
8849
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-field-order", children: fieldIndex + 1 }),
8850
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "orion-admin-field-editor-title", children: label }),
8851
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "orion-admin-field-editor-meta", children: [
8852
+ formatFieldTypeLabel(fieldType),
8853
+ field.required === true ? " \xB7 Required" : ""
8854
+ ] })
8855
+ ] }),
8856
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-field-editor-body", children: [
8857
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-step-editor-actions", children: [
8858
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8859
+ "button",
8860
+ {
8861
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
8862
+ disabled: fieldIndex === 0,
8863
+ onClick: () => moveField(stepIndex, fieldIndex, -1),
8864
+ type: "button",
8865
+ children: "Move up"
8866
+ }
8867
+ ),
8868
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8869
+ "button",
8870
+ {
8871
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
8872
+ disabled: fieldIndex === fields.length - 1,
8873
+ onClick: () => moveField(stepIndex, fieldIndex, 1),
8874
+ type: "button",
8875
+ children: "Move down"
8876
+ }
8877
+ ),
8878
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8879
+ "button",
8880
+ {
8881
+ className: "orion-admin-action-button orion-admin-action-button--ghost",
8882
+ onClick: () => setEditorState((current) => {
8883
+ if (!current) return current;
8884
+ return {
8885
+ ...current,
8886
+ steps: current.steps.map(
8887
+ (currentStep, index) => index === stepIndex ? {
8888
+ ...currentStep,
8889
+ fields: getFields(currentStep).filter(
8890
+ (_, currentFieldIndex) => currentFieldIndex !== fieldIndex
8891
+ )
8892
+ } : currentStep
8893
+ )
8894
+ };
8895
+ }),
8896
+ type: "button",
8897
+ children: "Remove field"
8898
+ }
8899
+ )
8900
+ ] }),
8901
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-step-settings-grid", children: [
8902
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8903
+ "Field label",
8904
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8905
+ "input",
8906
+ {
8907
+ onChange: (event) => {
8908
+ const nextLabel = event.target.value;
8909
+ const currentName = getNonEmptyText(field.name);
8910
+ updateField(stepIndex, fieldIndex, {
8911
+ label: nextLabel,
8912
+ name: currentName || slugifyFieldName(nextLabel)
8913
+ });
8914
+ },
8915
+ type: "text",
8916
+ value: label
8917
+ }
8918
+ )
8919
+ ] }),
8920
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8921
+ "Field type",
8922
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8923
+ "select",
8924
+ {
8925
+ onChange: (event) => updateField(stepIndex, fieldIndex, { type: event.target.value }),
8926
+ value: fieldType,
8927
+ children: fieldTypeOptions.map((option) => /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: option, children: formatFieldTypeLabel(option) }, option))
8928
+ }
8929
+ )
8930
+ ] })
8931
+ ] }),
8932
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8933
+ "Field key",
8934
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8935
+ "input",
8936
+ {
8937
+ onChange: (event) => updateField(stepIndex, fieldIndex, { name: event.target.value }),
8938
+ type: "text",
8939
+ value: getNonEmptyText(field.name)
8940
+ }
8941
+ )
8942
+ ] }),
8943
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { style: checkboxLabelStyle, children: [
8944
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8945
+ "input",
8946
+ {
8947
+ checked: field.required === true,
8948
+ onChange: (event) => updateField(stepIndex, fieldIndex, { required: event.target.checked }),
8949
+ type: "checkbox"
8950
+ }
8951
+ ),
8952
+ "Required"
8953
+ ] }),
8954
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8955
+ "Help text",
8956
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8957
+ "textarea",
8958
+ {
8959
+ onChange: (event) => updateField(stepIndex, fieldIndex, { helpText: event.target.value }),
8960
+ rows: 2,
8961
+ value: getNonEmptyText(field.helpText)
8962
+ }
8963
+ )
8964
+ ] }),
8965
+ ["select", "radio", "checkbox-group"].includes(fieldType) ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
8966
+ "Options",
8967
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8968
+ "textarea",
8969
+ {
8970
+ onChange: (event) => updateField(stepIndex, fieldIndex, {
8971
+ options: fromOptionsText(event.target.value)
8972
+ }),
8973
+ placeholder: "Option one\nOption two",
8974
+ rows: 4,
8975
+ value: toOptionsText(field.options)
8976
+ }
8977
+ )
8978
+ ] }) : null
8979
+ ] })
8980
+ ] }, `edit-field-${stepIndex}-${fieldIndex}`);
8981
+ }) }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-empty-state", children: [
8982
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "No fields in this step" }),
8983
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "Add a field so visitors have something to answer here." })
8984
+ ] })
8985
+ ] })
8986
+ ] }, `edit-step-${stepIndex}`);
8987
+ }) })
8988
+ ] }),
8989
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("button", { disabled: saving, type: "submit", children: saving ? "Saving..." : "Save Form" })
8990
+ ] })
8991
+ ] })
8992
+ ] }) : null
8993
+ ]
8994
+ }
8995
+ ) });
8996
+ }
8997
+
8998
+ // src/admin/components/studio/AdminStudioFormSubmissionView.tsx
8999
+ var import_link5 = __toESM(require("next/link"));
9000
+ var import_react33 = require("react");
9001
+ var import_jsx_runtime42 = require("react/jsx-runtime");
9002
+ var sectionGridStyle2 = {
9003
+ display: "grid",
9004
+ gap: "1rem",
9005
+ gridTemplateColumns: "repeat(auto-fit, minmax(320px, 1fr))"
9006
+ };
9007
+ var nestedListStyle = {
9008
+ display: "grid",
9009
+ gap: "0.45rem",
9010
+ margin: 0,
9011
+ padding: 0
9012
+ };
9013
+ var renderFieldValue = (value) => {
9014
+ if (value === null || value === void 0) {
9015
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-list-meta", children: "No value" });
9016
+ }
9017
+ if (typeof value === "boolean") {
9018
+ return value ? "Yes" : "No";
9019
+ }
9020
+ if (typeof value === "number") {
9021
+ return String(value);
9022
+ }
9023
+ if (typeof value === "string") {
9024
+ return value.trim().length > 0 ? value : /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-list-meta", children: "No value" });
9025
+ }
9026
+ if (Array.isArray(value)) {
9027
+ const entries = value.filter((entry) => entry !== null && entry !== void 0 && entry !== "");
9028
+ if (entries.length === 0) {
9029
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-list-meta", children: "No value" });
9030
+ }
9031
+ 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)) });
9032
+ }
9033
+ if (typeof value === "object") {
9034
+ const entries = Object.entries(value).filter(
9035
+ ([, entryValue]) => entryValue !== null && entryValue !== void 0 && entryValue !== ""
9036
+ );
9037
+ if (entries.length === 0) {
9038
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-list-meta", children: "No value" });
9039
+ }
9040
+ 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: [
9041
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-label", children: humanizeKey2(key) }),
9042
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-value", children: renderFieldValue(entryValue) })
9043
+ ] }, key)) });
9044
+ }
9045
+ return String(value);
9046
+ };
9047
+ function getSubmissionIDFromPathname(pathname) {
9048
+ return getIDFromPathname(pathname, "/forms/submissions/");
9049
+ }
9050
+ function AdminStudioFormSubmissionView(props) {
9051
+ const formsCollectionSlug = getPropString14(props, "formsCollectionSlug", "forms");
9052
+ const formSubmissionsCollectionSlug = getPropString14(
9053
+ props,
9054
+ "formSubmissionsCollectionSlug",
9055
+ "form-submissions"
9056
+ );
9057
+ const adminBasePath = useAdminBasePath();
9058
+ const formsPath = resolveAdminPath(adminBasePath, "/forms");
9059
+ const submissionIDFromParams = (0, import_react33.useMemo)(() => getParam3(props.params, "id"), [props.params]);
9060
+ const [submissionID, setSubmissionID] = (0, import_react33.useState)(submissionIDFromParams);
9061
+ const [didResolvePathFallback, setDidResolvePathFallback] = (0, import_react33.useState)(false);
9062
+ const [doc, setDoc] = (0, import_react33.useState)(null);
9063
+ const [formDoc, setFormDoc] = (0, import_react33.useState)(null);
9064
+ const [loading, setLoading] = (0, import_react33.useState)(true);
9065
+ const [error, setError] = (0, import_react33.useState)(null);
9066
+ const [confirmDelete, setConfirmDelete] = (0, import_react33.useState)(false);
9067
+ const [deleting, setDeleting] = (0, import_react33.useState)(false);
9068
+ (0, import_react33.useEffect)(() => {
9069
+ if (submissionIDFromParams) {
9070
+ setSubmissionID(submissionIDFromParams);
9071
+ setDidResolvePathFallback(true);
9072
+ return;
9073
+ }
9074
+ if (typeof window !== "undefined") {
9075
+ setSubmissionID(getSubmissionIDFromPathname(window.location.pathname));
9076
+ }
9077
+ setDidResolvePathFallback(true);
9078
+ }, [submissionIDFromParams]);
9079
+ const loadDoc = async (id) => {
9080
+ setLoading(true);
9081
+ setError(null);
9082
+ try {
9083
+ const response = await fetch(
9084
+ `/api/${formSubmissionsCollectionSlug}/${encodeURIComponent(id)}?depth=2&draft=true`,
9085
+ {
9086
+ credentials: "include"
9087
+ }
9088
+ );
9089
+ if (!response.ok) {
9090
+ throw new Error(`Failed to load submission (${response.status}).`);
9091
+ }
9092
+ const nextDoc = await response.json();
9093
+ const relatedForm = nextDoc.form && typeof nextDoc.form === "object" && !Array.isArray(nextDoc.form) ? nextDoc.form : null;
9094
+ let nextFormDoc = relatedForm;
9095
+ const relatedFormID2 = getFormID3(nextDoc.form);
9096
+ if (!nextFormDoc && relatedFormID2) {
9097
+ const formResponse = await fetch(
9098
+ `/api/${formsCollectionSlug}/${encodeURIComponent(relatedFormID2)}?depth=0&draft=true`,
9099
+ {
9100
+ credentials: "include"
9101
+ }
9102
+ );
9103
+ if (formResponse.ok) {
9104
+ nextFormDoc = await formResponse.json();
9105
+ }
9106
+ }
9107
+ setDoc(nextDoc);
9108
+ setFormDoc(nextFormDoc);
9109
+ } catch (loadError) {
9110
+ setError(loadError instanceof Error ? loadError.message : "Failed to load submission.");
9111
+ setDoc(null);
9112
+ setFormDoc(null);
9113
+ } finally {
9114
+ setLoading(false);
9115
+ }
9116
+ };
9117
+ (0, import_react33.useEffect)(() => {
9118
+ if (!submissionID) {
9119
+ return;
9120
+ }
9121
+ void loadDoc(submissionID);
9122
+ }, [formsCollectionSlug, formSubmissionsCollectionSlug, submissionID]);
9123
+ const deleteSubmission = async () => {
9124
+ if (!submissionID) {
9125
+ return;
9126
+ }
9127
+ setDeleting(true);
9128
+ setError(null);
9129
+ try {
9130
+ const response = await fetch(`/api/${formSubmissionsCollectionSlug}/${encodeURIComponent(submissionID)}`, {
9131
+ credentials: "include",
9132
+ method: "DELETE"
9133
+ });
9134
+ if (!response.ok) {
9135
+ throw new Error(`Failed to delete submission (${response.status}).`);
9136
+ }
9137
+ const relatedFormID2 = doc ? getFormID3(doc.form) : "";
9138
+ const targetHref = relatedFormID2 ? resolveAdminPath(adminBasePath, `/forms/${relatedFormID2}`) : formsPath;
9139
+ window.location.assign(targetHref);
9140
+ } catch (deleteError) {
9141
+ setError(deleteError instanceof Error ? deleteError.message : "Failed to delete submission.");
9142
+ setDeleting(false);
9143
+ }
9144
+ };
9145
+ if (!submissionID && !didResolvePathFallback) {
9146
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
9147
+ AdminPage,
9148
+ {
9149
+ breadcrumbs: [
9150
+ { label: "Dashboard", href: adminBasePath },
9151
+ { label: "Forms", href: formsPath },
9152
+ { label: "Submission" }
9153
+ ],
9154
+ description: "Loading submission workspace...",
9155
+ title: "Submission",
9156
+ children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_jsx_runtime42.Fragment, {})
9157
+ }
9158
+ ) });
9159
+ }
9160
+ const relatedFormID = doc ? getFormID3(doc.form) : "";
9161
+ const formPath = relatedFormID ? resolveAdminPath(adminBasePath, `/forms/${relatedFormID}`) : formsPath;
9162
+ const formTitle = formDoc ? getFormTitle2(formDoc) : getFormTitle2(doc?.formSlug);
9163
+ const uploads = doc ? getUploads2(doc.files) : [];
9164
+ const identity = doc ? getNameAndEmail2(doc.data) : {};
9165
+ const fieldLabels = formDoc ? buildFieldLabelMap2(formDoc) : /* @__PURE__ */ new Map();
9166
+ const previewFields = doc ? getPreviewFields2(doc.data, fieldLabels) : [];
9167
+ const answerEntries = doc && doc.data && typeof doc.data === "object" ? Object.entries(doc.data) : [];
9168
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
9169
+ AdminPage,
9170
+ {
9171
+ breadcrumbs: [
9172
+ { label: "Dashboard", href: adminBasePath },
9173
+ { label: "Forms", href: formsPath },
9174
+ ...relatedFormID ? [{ label: formTitle, href: formPath }] : [{ label: formTitle }],
9175
+ { label: "Submission" }
9176
+ ],
9177
+ description: "Review the submitted answers, related files, and linked form details.",
9178
+ title: "Submission",
9179
+ children: [
9180
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "orion-admin-list-meta", children: "Loading..." }) : null,
9181
+ error ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "orion-admin-error", children: error }) : null,
9182
+ !loading && !error && doc && submissionID ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { style: { display: "grid", gap: "1rem" }, children: [
9183
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-forms-summary-grid", children: [
9184
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("article", { className: "orion-admin-overview-stat", children: [
9185
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-overview-stat-label", children: "Submitted" }),
9186
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: formatDate2(doc.submittedAt) }),
9187
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { children: "Captured timestamp for this response." })
9188
+ ] }),
9189
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("article", { className: "orion-admin-overview-stat", children: [
9190
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-overview-stat-label", children: "Uploads" }),
9191
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: uploads.length }),
9192
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { children: "Files attached by the submitter." })
9193
+ ] }),
9194
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("article", { className: "orion-admin-overview-stat", children: [
9195
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-overview-stat-label", children: "Highlighted answers" }),
9196
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: previewFields.length }),
9197
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { children: "Readable answer previews from this response." })
9198
+ ] })
9199
+ ] }),
9200
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { style: sectionGridStyle2, children: [
9201
+ /* @__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: [
9202
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: "Response details" }),
9203
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { children: "Formatted answers using the current form field labels when available." }),
9204
+ /* @__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: [
9205
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { children: [
9206
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: fieldLabels.get(key) || humanizeKey2(key) }),
9207
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "orion-admin-list-meta", children: key })
9208
+ ] }),
9209
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { children: renderFieldValue(value) })
9210
+ ] }, key)) : /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-empty-state", children: [
9211
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: "No answers available" }),
9212
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { children: "This submission does not contain visible response details." })
9213
+ ] }) })
9214
+ ] }) }),
9215
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { style: { display: "grid", gap: "1rem" }, children: [
9216
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-card orion-admin-meta-table", children: [
9217
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-meta-row", children: [
9218
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-label", children: "Form" }),
9219
+ /* @__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 })
9220
+ ] }),
9221
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-meta-row", children: [
9222
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-label", children: "Primary contact" }),
9223
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-value", children: identity.name || identity.email || "Unknown" })
9224
+ ] }),
9225
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-meta-row", children: [
9226
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-label", children: "Email" }),
9227
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-value", children: identity.email || "Not provided" })
9228
+ ] }),
9229
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-meta-row", children: [
9230
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-label", children: "Submission ID" }),
9231
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-value", children: submissionID })
9232
+ ] }),
9233
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-meta-row", children: [
9234
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-meta-label", children: "Form slug" }),
9235
+ /* @__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" })
9236
+ ] })
9237
+ ] }),
9238
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-card", children: [
9239
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: "Attached uploads" }),
9240
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { children: "Files linked to this response remain inside the Studio workspace." }),
9241
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { style: { display: "grid", gap: "0.75rem", marginTop: "1rem" }, children: uploads.length > 0 ? uploads.map((upload) => {
9242
+ const uploadID = typeof upload.id === "string" || typeof upload.id === "number" ? String(upload.id) : "";
9243
+ if (!uploadID) return null;
9244
+ const uploadPath = resolveAdminPath(adminBasePath, `/forms/uploads/${uploadID}`);
9245
+ const meta = [formatFileSize4(upload.filesize), typeof upload.mimeType === "string" ? upload.mimeType : null].filter(Boolean).join(" \xB7 ");
9246
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_link5.default, { className: "orion-admin-list-item", href: uploadPath, children: [
9247
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { children: [
9248
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: typeof upload.filename === "string" && upload.filename.trim().length > 0 ? upload.filename : `Upload ${uploadID}` }),
9249
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "orion-admin-list-meta", children: meta || "Open file details" })
9250
+ ] }),
9251
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "orion-admin-action-button orion-admin-action-button--ghost", children: "Open" })
9252
+ ] }, uploadID);
9253
+ }) : /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-empty-state", children: [
9254
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("strong", { children: "No files attached" }),
9255
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { children: "This response did not include any uploads." })
9256
+ ] }) })
9257
+ ] }),
9258
+ confirmDelete ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-form", style: { borderColor: "#b42318" }, children: [
9259
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { style: { fontWeight: 700, margin: 0 }, children: "Delete this submission?" }),
9260
+ /* @__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." }),
9261
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "orion-admin-inline-actions", children: [
9262
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("button", { disabled: deleting, onClick: deleteSubmission, type: "button", children: deleting ? "Deleting..." : "Yes, Delete" }),
9263
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("button", { onClick: () => setConfirmDelete(false), type: "button", children: "Cancel" })
9264
+ ] })
9265
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
9266
+ "button",
9267
+ {
9268
+ className: "orion-admin-action-button",
9269
+ onClick: () => setConfirmDelete(true),
9270
+ style: { background: "#b42318" },
9271
+ type: "button",
9272
+ children: "Delete Submission"
9273
+ }
9274
+ )
9275
+ ] })
9276
+ ] })
9277
+ ] }) : null
9278
+ ]
9279
+ }
9280
+ ) });
9281
+ }
9282
+
9283
+ // src/admin/components/studio/AdminStudioFormUploadView.tsx
9284
+ var import_react34 = require("react");
9285
+ var import_jsx_runtime43 = require("react/jsx-runtime");
9286
+ var previewStyle = {
9287
+ borderRadius: 14,
9288
+ display: "block",
9289
+ maxHeight: "28rem",
9290
+ objectFit: "contain",
9291
+ width: "100%"
9292
+ };
9293
+ function getUploadIDFromPathname(pathname) {
9294
+ return getIDFromPathname(pathname, "/forms/uploads/");
9295
+ }
9296
+ function AdminStudioFormUploadView(props) {
9297
+ const formUploadsCollectionSlug = getPropString14(props, "formUploadsCollectionSlug", "form-uploads");
9298
+ const adminBasePath = useAdminBasePath();
9299
+ const formsPath = resolveAdminPath(adminBasePath, "/forms");
9300
+ const uploadIDFromParams = (0, import_react34.useMemo)(() => getParam3(props.params, "id"), [props.params]);
9301
+ const [uploadID, setUploadID] = (0, import_react34.useState)(uploadIDFromParams);
9302
+ const [didResolvePathFallback, setDidResolvePathFallback] = (0, import_react34.useState)(false);
9303
+ const [doc, setDoc] = (0, import_react34.useState)(null);
9304
+ const [loading, setLoading] = (0, import_react34.useState)(true);
9305
+ const [error, setError] = (0, import_react34.useState)(null);
9306
+ const [savedMessage, setSavedMessage] = (0, import_react34.useState)(null);
9307
+ const [saving, setSaving] = (0, import_react34.useState)(false);
9308
+ const [confirmDelete, setConfirmDelete] = (0, import_react34.useState)(false);
9309
+ const [deleting, setDeleting] = (0, import_react34.useState)(false);
9310
+ (0, import_react34.useEffect)(() => {
9311
+ if (uploadIDFromParams) {
9312
+ setUploadID(uploadIDFromParams);
9313
+ setDidResolvePathFallback(true);
9314
+ return;
9315
+ }
9316
+ if (typeof window !== "undefined") {
9317
+ setUploadID(getUploadIDFromPathname(window.location.pathname));
9318
+ }
9319
+ setDidResolvePathFallback(true);
9320
+ }, [uploadIDFromParams]);
9321
+ const loadDoc = async (id) => {
9322
+ setLoading(true);
9323
+ setError(null);
9324
+ try {
9325
+ const response = await fetch(`/api/${formUploadsCollectionSlug}/${encodeURIComponent(id)}?depth=0&draft=true`, {
9326
+ credentials: "include"
9327
+ });
9328
+ if (!response.ok) {
9329
+ throw new Error(`Failed to load upload (${response.status}).`);
9330
+ }
9331
+ const nextDoc = await response.json();
9332
+ setDoc(nextDoc);
9333
+ } catch (loadError) {
9334
+ setError(loadError instanceof Error ? loadError.message : "Failed to load upload.");
9335
+ setDoc(null);
9336
+ } finally {
9337
+ setLoading(false);
9338
+ }
9339
+ };
9340
+ (0, import_react34.useEffect)(() => {
9341
+ if (!uploadID) {
9342
+ return;
9343
+ }
9344
+ void loadDoc(uploadID);
9345
+ }, [formUploadsCollectionSlug, uploadID]);
9346
+ const save = async (event) => {
9347
+ event.preventDefault();
9348
+ if (!uploadID) {
9349
+ return;
9350
+ }
9351
+ setSaving(true);
9352
+ setError(null);
9353
+ setSavedMessage(null);
9354
+ try {
9355
+ const formData = new FormData(event.currentTarget);
9356
+ const alt = String(formData.get("alt") || "").trim();
9357
+ const response = await fetch(`/api/${formUploadsCollectionSlug}/${encodeURIComponent(uploadID)}`, {
9358
+ body: JSON.stringify({ alt }),
9359
+ credentials: "include",
9360
+ headers: {
9361
+ "Content-Type": "application/json"
9362
+ },
9363
+ method: "PATCH"
9364
+ });
9365
+ if (!response.ok) {
9366
+ throw new Error(`Failed to save upload (${response.status}).`);
9367
+ }
9368
+ const nextDoc = await response.json();
9369
+ setDoc(nextDoc);
9370
+ setSavedMessage("Saved.");
9371
+ } catch (saveError) {
9372
+ setError(saveError instanceof Error ? saveError.message : "Failed to save upload.");
9373
+ } finally {
9374
+ setSaving(false);
9375
+ }
9376
+ };
9377
+ const deleteUpload = async () => {
9378
+ if (!uploadID) {
9379
+ return;
9380
+ }
9381
+ setDeleting(true);
9382
+ setError(null);
9383
+ try {
9384
+ const response = await fetch(`/api/${formUploadsCollectionSlug}/${encodeURIComponent(uploadID)}`, {
9385
+ credentials: "include",
9386
+ method: "DELETE"
9387
+ });
9388
+ if (!response.ok) {
9389
+ throw new Error(`Failed to delete upload (${response.status}).`);
9390
+ }
9391
+ window.location.assign(formsPath);
9392
+ } catch (deleteError) {
9393
+ setError(deleteError instanceof Error ? deleteError.message : "Failed to delete upload.");
9394
+ setDeleting(false);
9395
+ }
9396
+ };
9397
+ if (!uploadID && !didResolvePathFallback) {
9398
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
9399
+ AdminPage,
9400
+ {
9401
+ breadcrumbs: [
9402
+ { label: "Dashboard", href: adminBasePath },
9403
+ { label: "Forms", href: formsPath },
9404
+ { label: "Upload" }
9405
+ ],
9406
+ description: "Loading upload workspace...",
9407
+ title: "Upload",
9408
+ children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_jsx_runtime43.Fragment, {})
9409
+ }
9410
+ ) });
9411
+ }
9412
+ const filename = doc && typeof doc.filename === "string" && doc.filename.trim().length > 0 ? doc.filename : uploadID ? `Upload ${uploadID}` : "Upload";
9413
+ const mimeType = doc && typeof doc.mimeType === "string" ? doc.mimeType : "";
9414
+ const sourceURL = doc && typeof doc.url === "string" && doc.url.trim().length > 0 ? doc.url : null;
9415
+ const canPreview = Boolean(sourceURL && mimeType.startsWith("image/"));
9416
+ const createdAt = doc?.createdAt ?? doc?.updatedAt;
9417
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
9418
+ AdminPage,
9419
+ {
9420
+ breadcrumbs: [
9421
+ { label: "Dashboard", href: adminBasePath },
9422
+ { label: "Forms", href: formsPath },
9423
+ { label: filename }
9424
+ ],
9425
+ description: "Review file metadata, update alt text, and remove private uploads from Studio.",
9426
+ title: "Upload",
9427
+ children: [
9428
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "orion-admin-list-meta", children: "Loading..." }) : null,
9429
+ error ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "orion-admin-error", children: error }) : null,
9430
+ savedMessage ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "orion-admin-success", children: savedMessage }) : null,
9431
+ !loading && !error && doc && uploadID ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "orion-admin-grid", style: { alignItems: "start" }, children: [
9432
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { style: { display: "grid", gap: "0.8rem" }, children: [
9433
+ /* @__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: [
9434
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("strong", { children: "No inline preview" }),
9435
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { children: mimeType ? `Preview unavailable for ${mimeType}.` : "Preview unavailable for this file." })
9436
+ ] }) }),
9437
+ sourceURL ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("a", { className: "orion-admin-action-button", href: sourceURL, rel: "noreferrer", target: "_blank", children: "Open File" }) : null
9438
+ ] }),
9439
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { style: { display: "grid", gap: "0.8rem" }, children: [
9440
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "orion-admin-card orion-admin-meta-table", children: [
9441
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "orion-admin-meta-row", children: [
9442
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "orion-admin-meta-label", children: "Filename" }),
9443
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "orion-admin-meta-value", children: filename })
9444
+ ] }),
9445
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "orion-admin-meta-row", children: [
9446
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "orion-admin-meta-label", children: "File size" }),
9447
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "orion-admin-meta-value", children: formatFileSize4(doc.filesize) || "Unavailable" })
9448
+ ] }),
9449
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "orion-admin-meta-row", children: [
9450
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "orion-admin-meta-label", children: "Type" }),
9451
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "orion-admin-meta-value", children: mimeType || "Unavailable" })
9452
+ ] }),
9453
+ typeof doc.width === "number" && typeof doc.height === "number" ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "orion-admin-meta-row", children: [
9454
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "orion-admin-meta-label", children: "Dimensions" }),
9455
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "orion-admin-meta-value", children: [
9456
+ doc.width,
9457
+ " x ",
9458
+ doc.height,
9459
+ "px"
9460
+ ] })
9461
+ ] }) : null,
9462
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "orion-admin-meta-row", children: [
9463
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "orion-admin-meta-label", children: "Uploaded" }),
9464
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "orion-admin-meta-value", children: formatDate2(createdAt) })
9465
+ ] })
9466
+ ] }),
9467
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("form", { className: "orion-admin-form", onSubmit: save, children: [
9468
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("strong", { children: "Asset details" }),
9469
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("label", { children: [
9470
+ "Alt text",
9471
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("input", { defaultValue: typeof doc.alt === "string" ? doc.alt : "", name: "alt", type: "text" })
9472
+ ] }),
9473
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", { disabled: saving, type: "submit", children: saving ? "Saving..." : "Save Upload" })
9474
+ ] }),
9475
+ confirmDelete ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "orion-admin-form", style: { borderColor: "#b42318" }, children: [
9476
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { style: { fontWeight: 700, margin: 0 }, children: "Delete this upload?" }),
9477
+ /* @__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." }),
9478
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "orion-admin-inline-actions", children: [
9479
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", { disabled: deleting, onClick: deleteUpload, type: "button", children: deleting ? "Deleting..." : "Yes, Delete" }),
9480
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", { onClick: () => setConfirmDelete(false), type: "button", children: "Cancel" })
9481
+ ] })
9482
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
9483
+ "button",
9484
+ {
9485
+ className: "orion-admin-action-button",
9486
+ onClick: () => setConfirmDelete(true),
9487
+ style: { background: "#b42318" },
9488
+ type: "button",
9489
+ children: "Delete Upload"
9490
+ }
9491
+ )
9492
+ ] })
9493
+ ] }) : null
9494
+ ]
9495
+ }
9496
+ ) });
9497
+ }
9498
+
9499
+ // src/admin/components/studio/AdminStudioToolsView.tsx
9500
+ var import_react35 = require("react");
9501
+ var import_ui12 = require("@payloadcms/ui");
9502
+ var import_jsx_runtime44 = require("react/jsx-runtime");
9503
+ var userRoles = ["admin", "developer", "editor", "client"];
9504
+ var hasAdminAccess3 = (user) => {
9505
+ if (!user || typeof user !== "object") return false;
9506
+ const role = user.role;
9507
+ return typeof role === "string" && (role === "admin" || role === "developer");
9508
+ };
9509
+ var normalizeRole = (value) => userRoles.includes(value) ? value : "editor";
9510
+ function AdminStudioToolsView(props) {
9511
+ const { user } = (0, import_ui12.useAuth)();
9512
+ const adminBasePath = useAdminBasePath();
9513
+ const [docs, setDocs] = (0, import_react35.useState)([]);
9514
+ const [loading, setLoading] = (0, import_react35.useState)(true);
9515
+ const [error, setError] = (0, import_react35.useState)(null);
9516
+ const [savedMessage, setSavedMessage] = (0, import_react35.useState)(null);
9517
+ const [createSubmitting, setCreateSubmitting] = (0, import_react35.useState)(false);
9518
+ const [updatingUserID, setUpdatingUserID] = (0, import_react35.useState)(null);
9519
+ if (!hasAdminAccess3(user)) {
9520
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
9521
+ AdminPage,
9522
+ {
9523
+ breadcrumbs: [
9524
+ { label: "Dashboard", href: adminBasePath },
9525
+ { label: "Admin Tools" }
9526
+ ],
9527
+ description: "You do not have access to this section.",
9528
+ title: "Admin Tools",
9529
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "orion-admin-card", children: [
9530
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("strong", { children: "Access denied" }),
9531
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { children: "This section is restricted to administrator and developer accounts." })
9532
+ ] })
9533
+ }
9534
+ ) });
9535
+ }
9536
+ const loadUsers = async () => {
9537
+ setLoading(true);
9538
+ setError(null);
9539
+ try {
9540
+ const params = new URLSearchParams({
9541
+ depth: "0",
9542
+ draft: "true",
8061
9543
  limit: "200",
8062
9544
  sort: "email"
8063
9545
  });
@@ -8075,16 +9557,17 @@ function AdminStudioToolsView(props) {
8075
9557
  setLoading(false);
8076
9558
  }
8077
9559
  };
8078
- (0, import_react32.useEffect)(() => {
9560
+ (0, import_react35.useEffect)(() => {
8079
9561
  void loadUsers();
8080
9562
  }, []);
8081
9563
  const createUser = async (event) => {
8082
9564
  event.preventDefault();
9565
+ const form = event.currentTarget;
8083
9566
  setCreateSubmitting(true);
8084
9567
  setError(null);
8085
9568
  setSavedMessage(null);
8086
9569
  try {
8087
- const formData = new FormData(event.currentTarget);
9570
+ const formData = new FormData(form);
8088
9571
  const email = String(formData.get("email") || "").trim();
8089
9572
  const password = String(formData.get("password") || "");
8090
9573
  const fullName = String(formData.get("fullName") || "").trim();
@@ -8108,7 +9591,7 @@ function AdminStudioToolsView(props) {
8108
9591
  if (!response.ok) {
8109
9592
  throw new Error(`Failed to create user (${response.status}).`);
8110
9593
  }
8111
- event.currentTarget.reset();
9594
+ form.reset();
8112
9595
  await loadUsers();
8113
9596
  setSavedMessage("User created.");
8114
9597
  } catch (createError) {
@@ -8146,7 +9629,7 @@ function AdminStudioToolsView(props) {
8146
9629
  setUpdatingUserID(null);
8147
9630
  }
8148
9631
  };
8149
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
9632
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
8150
9633
  AdminPage,
8151
9634
  {
8152
9635
  breadcrumbs: [
@@ -8156,53 +9639,44 @@ function AdminStudioToolsView(props) {
8156
9639
  description: "Manage users and fallback links to Payload native admin.",
8157
9640
  title: "Admin Tools",
8158
9641
  children: [
8159
- /* @__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" }) }),
8160
- error ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-error", style: { marginBottom: "1rem" }, children: error }) : null,
8161
- savedMessage ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-success", style: { marginBottom: "1rem" }, children: savedMessage }) : null,
8162
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("form", { className: "orion-admin-form", onSubmit: createUser, style: { marginBottom: "1rem" }, children: [
8163
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "Create User" }),
8164
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
9642
+ error ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "orion-admin-error", style: { marginBottom: "1rem" }, children: error }) : null,
9643
+ savedMessage ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "orion-admin-success", style: { marginBottom: "1rem" }, children: savedMessage }) : null,
9644
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("form", { className: "orion-admin-form", onSubmit: createUser, style: { marginBottom: "1rem" }, children: [
9645
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("strong", { children: "Create User" }),
9646
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("label", { children: [
8165
9647
  "Email",
8166
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("input", { name: "email", required: true, type: "email" })
9648
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("input", { name: "email", required: true, type: "email" })
8167
9649
  ] }),
8168
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
9650
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("label", { children: [
8169
9651
  "Full Name",
8170
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("input", { name: "fullName", type: "text" })
9652
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("input", { name: "fullName", type: "text" })
8171
9653
  ] }),
8172
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
9654
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("label", { children: [
8173
9655
  "Password",
8174
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("input", { name: "password", required: true, type: "password" })
9656
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("input", { name: "password", required: true, type: "password" })
8175
9657
  ] }),
8176
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { children: [
9658
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("label", { children: [
8177
9659
  "Role",
8178
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("select", { defaultValue: "editor", name: "role", children: [
8179
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: "admin", children: "admin" }),
8180
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: "editor", children: "editor" }),
8181
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: "client", children: "client" })
8182
- ] })
9660
+ /* @__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)) })
8183
9661
  ] }),
8184
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("button", { disabled: createSubmitting, type: "submit", children: createSubmitting ? "Creating..." : "Create User" })
9662
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("button", { disabled: createSubmitting, type: "submit", children: createSubmitting ? "Creating..." : "Create User" })
8185
9663
  ] }),
8186
- loading ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-list-meta", children: "Loading..." }) : null,
8187
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-list", children: docs.map((doc) => {
9664
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "orion-admin-list-meta", children: "Loading..." }) : null,
9665
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "orion-admin-list", children: docs.map((doc) => {
8188
9666
  const id = typeof doc.id === "string" || typeof doc.id === "number" ? String(doc.id) : "";
8189
9667
  if (!id) return null;
8190
9668
  const email = typeof doc.email === "string" ? doc.email : `user-${id}`;
8191
9669
  const fullName = typeof doc.fullName === "string" ? doc.fullName : "";
8192
9670
  const currentRole = typeof doc.role === "string" ? normalizeRole(doc.role) : "editor";
8193
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-list-item", children: [
8194
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { children: [
8195
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: email }),
8196
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "orion-admin-list-meta", children: fullName || "No full name set" })
9671
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "orion-admin-list-item", children: [
9672
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { children: [
9673
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("strong", { children: email }),
9674
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "orion-admin-list-meta", children: fullName || "No full name set" })
8197
9675
  ] }),
8198
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("form", { className: "orion-admin-inline-actions", onSubmit: updateUserRole, children: [
8199
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("input", { name: "id", type: "hidden", value: id }),
8200
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("select", { defaultValue: currentRole, name: "role", children: [
8201
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: "admin", children: "admin" }),
8202
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: "editor", children: "editor" }),
8203
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: "client", children: "client" })
8204
- ] }),
8205
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("button", { disabled: updatingUserID === id, type: "submit", children: updatingUserID === id ? "Updating..." : "Update" })
9676
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("form", { className: "orion-admin-inline-actions", onSubmit: updateUserRole, children: [
9677
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("input", { name: "id", type: "hidden", value: id }),
9678
+ /* @__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)) }),
9679
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("button", { disabled: updatingUserID === id, type: "submit", children: updatingUserID === id ? "Updating..." : "Update" })
8206
9680
  ] })
8207
9681
  ] }, id);
8208
9682
  }) })
@@ -8213,14 +9687,14 @@ function AdminStudioToolsView(props) {
8213
9687
 
8214
9688
  // src/admin/components/studio/OpenInStudioMenuItem.tsx
8215
9689
  var import_ui13 = require("@payloadcms/ui");
8216
- var import_jsx_runtime42 = require("react/jsx-runtime");
9690
+ var import_jsx_runtime45 = require("react/jsx-runtime");
8217
9691
  function OpenInStudioMenuItem({ pagesPathBase = "/pages" }) {
8218
9692
  const documentInfo = (0, import_ui13.useDocumentInfo)();
8219
9693
  const id = documentInfo?.id;
8220
9694
  if (!id) {
8221
9695
  return null;
8222
9696
  }
8223
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
9697
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
8224
9698
  "a",
8225
9699
  {
8226
9700
  href: `${pagesPathBase}/${id}`,
@@ -8239,19 +9713,19 @@ function OpenInStudioMenuItem({ pagesPathBase = "/pages" }) {
8239
9713
  }
8240
9714
 
8241
9715
  // src/admin/components/studio/PageEditRedirectToStudio.tsx
8242
- var import_react33 = require("react");
9716
+ var import_react36 = require("react");
8243
9717
  var import_ui14 = require("@payloadcms/ui");
8244
- var import_jsx_runtime43 = require("react/jsx-runtime");
9718
+ var import_jsx_runtime46 = require("react/jsx-runtime");
8245
9719
  function PageEditRedirectToStudio({ pagesPathBase = "/pages" }) {
8246
9720
  const documentInfo = (0, import_ui14.useDocumentInfo)();
8247
9721
  const id = documentInfo?.id;
8248
- (0, import_react33.useEffect)(() => {
9722
+ (0, import_react36.useEffect)(() => {
8249
9723
  if (!id) {
8250
9724
  return;
8251
9725
  }
8252
9726
  window.location.replace(`${pagesPathBase}/${id}`);
8253
9727
  }, [id, pagesPathBase]);
8254
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
9728
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
8255
9729
  "div",
8256
9730
  {
8257
9731
  style: {
@@ -8263,18 +9737,61 @@ function PageEditRedirectToStudio({ pagesPathBase = "/pages" }) {
8263
9737
  minHeight: "50vh"
8264
9738
  },
8265
9739
  children: [
8266
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("h2", { style: { margin: 0 }, children: "Opening Editor..." }),
8267
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { style: { color: "var(--theme-elevation-600)", margin: 0 }, children: "Redirecting to the custom page editor." }),
8268
- 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" })
9740
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("h2", { style: { margin: 0 }, children: "Opening Editor..." }),
9741
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("p", { style: { color: "var(--theme-elevation-600)", margin: 0 }, children: "Redirecting to the custom page editor." }),
9742
+ 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" })
8269
9743
  ]
8270
9744
  }
8271
9745
  );
8272
9746
  }
8273
9747
 
8274
- // src/admin/components/studio/StudioBackBreadcrumb.tsx
8275
- var import_react34 = require("react");
9748
+ // src/admin/components/studio/StudioDocumentRedirect.tsx
9749
+ var import_react37 = require("react");
8276
9750
  var import_ui15 = require("@payloadcms/ui");
8277
- var import_jsx_runtime44 = require("react/jsx-runtime");
9751
+ var import_jsx_runtime47 = require("react/jsx-runtime");
9752
+ function StudioDocumentRedirect({
9753
+ description = "Redirecting to the Studio view.",
9754
+ emptyHref,
9755
+ emptyLabel = "Open Studio",
9756
+ pathBase = "/forms",
9757
+ title = "Opening Studio..."
9758
+ }) {
9759
+ const adminBasePath = useAdminBasePath();
9760
+ const documentInfo = (0, import_ui15.useDocumentInfo)();
9761
+ const id = documentInfo?.id;
9762
+ const fallbackHref = resolveAdminPath(adminBasePath, emptyHref || pathBase);
9763
+ (0, import_react37.useEffect)(() => {
9764
+ if (!id) {
9765
+ return;
9766
+ }
9767
+ const targetHref = resolveAdminPath(adminBasePath, `${pathBase}/${encodeURIComponent(String(id))}`);
9768
+ window.location.replace(targetHref);
9769
+ }, [adminBasePath, id, pathBase]);
9770
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
9771
+ "div",
9772
+ {
9773
+ style: {
9774
+ alignItems: "center",
9775
+ display: "flex",
9776
+ flexDirection: "column",
9777
+ gap: "0.75rem",
9778
+ justifyContent: "center",
9779
+ minHeight: "50vh",
9780
+ textAlign: "center"
9781
+ },
9782
+ children: [
9783
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("h2", { style: { margin: 0 }, children: title }),
9784
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("p", { style: { color: "var(--theme-elevation-600)", margin: 0 }, children: description }),
9785
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("a", { href: fallbackHref, children: emptyLabel })
9786
+ ]
9787
+ }
9788
+ );
9789
+ }
9790
+
9791
+ // src/admin/components/studio/StudioBackBreadcrumb.tsx
9792
+ var import_react38 = require("react");
9793
+ var import_ui16 = require("@payloadcms/ui");
9794
+ var import_jsx_runtime48 = require("react/jsx-runtime");
8278
9795
  var toTitle = (slug) => slug.split("-").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
8279
9796
  var buildNav = (pathname, adminBasePath) => {
8280
9797
  if (pathname.includes("/globals/")) {
@@ -8319,8 +9836,8 @@ var buildNav = (pathname, adminBasePath) => {
8319
9836
  };
8320
9837
  function StudioBackBreadcrumb() {
8321
9838
  const adminBasePath = useAdminBasePath();
8322
- const [pathname, setPathname] = (0, import_react34.useState)("");
8323
- (0, import_react34.useEffect)(() => {
9839
+ const [pathname, setPathname] = (0, import_react38.useState)("");
9840
+ (0, import_react38.useEffect)(() => {
8324
9841
  const update = () => setPathname(window.location.pathname);
8325
9842
  update();
8326
9843
  window.addEventListener("popstate", update);
@@ -8328,13 +9845,13 @@ function StudioBackBreadcrumb() {
8328
9845
  }, []);
8329
9846
  const nav = buildNav(pathname, adminBasePath);
8330
9847
  if (!nav) return null;
8331
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_ui15.SetStepNav, { nav });
9848
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui16.SetStepNav, { nav });
8332
9849
  }
8333
9850
 
8334
9851
  // src/admin/components/studio/StudioContactFormRedirect.tsx
8335
- var import_react35 = require("react");
8336
- var import_jsx_runtime45 = require("react/jsx-runtime");
8337
- var getPropString14 = (props, key, fallback) => {
9852
+ var import_react39 = require("react");
9853
+ var import_jsx_runtime49 = require("react/jsx-runtime");
9854
+ var getPropString15 = (props, key, fallback) => {
8338
9855
  if (!props || typeof props !== "object") return fallback;
8339
9856
  const direct = props[key];
8340
9857
  if (typeof direct === "string" && direct.length > 0) return direct;
@@ -8347,13 +9864,13 @@ var getPropString14 = (props, key, fallback) => {
8347
9864
  };
8348
9865
  function StudioContactFormRedirect(props) {
8349
9866
  const adminBasePath = useAdminBasePath();
8350
- const studioContactFormPath = getPropString14(props, "studioContactFormPath", "/contact-form");
9867
+ const studioContactFormPath = getPropString15(props, "studioContactFormPath", "/contact-form");
8351
9868
  const targetPath = resolveAdminPath(adminBasePath, studioContactFormPath);
8352
- (0, import_react35.useEffect)(() => {
9869
+ (0, import_react39.useEffect)(() => {
8353
9870
  if (window.location.pathname === targetPath) return;
8354
9871
  window.location.replace(targetPath);
8355
9872
  }, [targetPath]);
8356
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
9873
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
8357
9874
  "div",
8358
9875
  {
8359
9876
  style: {
@@ -8366,8 +9883,8 @@ function StudioContactFormRedirect(props) {
8366
9883
  minHeight: "40vh"
8367
9884
  },
8368
9885
  children: [
8369
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h2", { style: { margin: 0 }, children: "Opening Contact Form Editor..." }),
8370
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("a", { href: targetPath, children: "Continue" })
9886
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("h2", { style: { margin: 0 }, children: "Opening Contact Form Editor..." }),
9887
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("a", { href: targetPath, children: "Continue" })
8371
9888
  ]
8372
9889
  }
8373
9890
  );
@@ -8379,6 +9896,9 @@ function StudioContactFormRedirect(props) {
8379
9896
  AdminStudioContactFormView,
8380
9897
  AdminStudioDashboard,
8381
9898
  AdminStudioFooterGlobalView,
9899
+ AdminStudioFormDetailView,
9900
+ AdminStudioFormSubmissionView,
9901
+ AdminStudioFormUploadView,
8382
9902
  AdminStudioFormsView,
8383
9903
  AdminStudioGlobalsView,
8384
9904
  AdminStudioHeaderGlobalView,
@@ -8404,6 +9924,7 @@ function StudioContactFormRedirect(props) {
8404
9924
  StatusBadge,
8405
9925
  StudioBackBreadcrumb,
8406
9926
  StudioContactFormRedirect,
9927
+ StudioDocumentRedirect,
8407
9928
  StudioSectionLayout,
8408
9929
  ThemeProvider,
8409
9930
  ThemeSwitcher,