@orion-studios/payload-studio 0.6.0-beta.12 → 0.6.0-beta.120
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/client.js +2062 -547
- package/dist/admin/client.mjs +2079 -577
- package/dist/admin/index.js +124 -15
- package/dist/admin/index.mjs +1 -1
- package/dist/admin-app/client.js +14 -5
- package/dist/admin-app/client.mjs +1 -1
- package/dist/admin-app/styles.css +277 -1
- package/dist/admin.css +98 -2
- package/dist/builder-v2/client.d.mts +18 -0
- package/dist/builder-v2/client.d.ts +18 -0
- package/dist/builder-v2/client.js +3617 -0
- package/dist/builder-v2/client.mjs +3492 -0
- package/dist/builder-v2/index.d.mts +242 -0
- package/dist/builder-v2/index.d.ts +242 -0
- package/dist/builder-v2/index.js +805 -0
- package/dist/builder-v2/index.mjs +755 -0
- package/dist/builder-v2/styles.css +2463 -0
- package/dist/{chunk-PF3EBZXF.mjs → chunk-7ZMXZRBP.mjs} +39 -3
- package/dist/{chunk-XZQILJK3.mjs → chunk-JC3UV74N.mjs} +124 -15
- package/dist/{chunk-KPIX7OSV.mjs → chunk-NF37A575.mjs} +14 -5
- package/dist/{chunk-XKUTZ7IU.mjs → chunk-NGLIA2OE.mjs} +53 -2
- package/dist/{chunk-OTHERBGX.mjs → chunk-ZADL33R6.mjs} +1 -1
- package/dist/{index-Cv-6qnrw.d.mts → index-D5zrOdyv.d.mts} +3 -1
- package/dist/{index-Crx_MtPw.d.ts → index-Dv-Alx4h.d.ts} +3 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +215 -19
- package/dist/index.mjs +4 -4
- package/dist/nextjs/index.js +39 -3
- package/dist/nextjs/index.mjs +2 -2
- package/dist/studio-pages/builder.css +66 -5
- package/dist/studio-pages/client.js +618 -73
- package/dist/studio-pages/client.mjs +641 -96
- package/dist/studio-pages/index.d.mts +1 -1
- package/dist/studio-pages/index.d.ts +1 -1
- package/dist/studio-pages/index.js +91 -4
- package/dist/studio-pages/index.mjs +2 -2
- package/package.json +22 -3
package/dist/admin/client.js
CHANGED
|
@@ -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:
|
|
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,
|
|
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 =
|
|
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,
|
|
955
|
+
[clientBlocks, getFields2, replaceState, safePath, setModified, t]
|
|
956
956
|
);
|
|
957
957
|
const pasteBlocks = (0, import_react10.useCallback)(
|
|
958
958
|
(dataFromClipboard) => {
|
|
959
|
-
const formState =
|
|
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
|
-
[
|
|
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:
|
|
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,
|
|
@@ -2869,8 +2873,26 @@ function NavIcon({ sectionID }) {
|
|
|
2869
2873
|
return null;
|
|
2870
2874
|
}
|
|
2871
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
|
+
}
|
|
2872
2893
|
function AdminStudioNav(props) {
|
|
2873
2894
|
const { user } = (0, import_ui3.useAuth)();
|
|
2895
|
+
const [loggingOut, setLoggingOut] = (0, import_react13.useState)(false);
|
|
2874
2896
|
const brandName = getPropString(props, "brandName", "Orion Studio");
|
|
2875
2897
|
const logoUrl = getPropString(props, "logoUrl", "");
|
|
2876
2898
|
const compact = getPropBoolean(props, "compact", false);
|
|
@@ -2881,6 +2903,18 @@ function AdminStudioNav(props) {
|
|
|
2881
2903
|
const dashboardPath = adminBasePath;
|
|
2882
2904
|
const userRole = readUserRole(user);
|
|
2883
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
|
+
};
|
|
2884
2918
|
if (isStudioShellRoute(pathname, props, adminBasePath)) {
|
|
2885
2919
|
return null;
|
|
2886
2920
|
}
|
|
@@ -2971,7 +3005,38 @@ function AdminStudioNav(props) {
|
|
|
2971
3005
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { color: "var(--theme-elevation-700)", fontSize: "0.85rem" }, children: "Signed in as" }),
|
|
2972
3006
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { fontWeight: 800, marginBottom: "0.55rem" }, children: typeof user?.email === "string" ? user.email : "User" })
|
|
2973
3007
|
] }) : null,
|
|
2974
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.
|
|
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
|
+
)
|
|
2975
3040
|
]
|
|
2976
3041
|
}
|
|
2977
3042
|
)
|
|
@@ -3044,6 +3109,14 @@ function NavIcon2({ name }) {
|
|
|
3044
3109
|
return null;
|
|
3045
3110
|
}
|
|
3046
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
|
+
}
|
|
3047
3120
|
function AdminShellClient({
|
|
3048
3121
|
children,
|
|
3049
3122
|
brandName,
|
|
@@ -3055,14 +3128,12 @@ function AdminShellClient({
|
|
|
3055
3128
|
onLogout,
|
|
3056
3129
|
storageKey = "orion-admin-shell-collapsed"
|
|
3057
3130
|
}) {
|
|
3058
|
-
const [collapsed, setCollapsed] = (0, import_react14.useState)(
|
|
3131
|
+
const [collapsed, setCollapsed] = (0, import_react14.useState)(true);
|
|
3059
3132
|
const [loggingOut, setLoggingOut] = (0, import_react14.useState)(false);
|
|
3060
3133
|
(0, import_react14.useEffect)(() => {
|
|
3061
3134
|
try {
|
|
3062
3135
|
const stored = window.localStorage.getItem(storageKey);
|
|
3063
|
-
|
|
3064
|
-
setCollapsed(true);
|
|
3065
|
-
}
|
|
3136
|
+
setCollapsed(stored === "1");
|
|
3066
3137
|
} catch {
|
|
3067
3138
|
}
|
|
3068
3139
|
}, [storageKey]);
|
|
@@ -3124,7 +3195,10 @@ function AdminShellClient({
|
|
|
3124
3195
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "orion-admin-user-label", children: "Signed in as" }),
|
|
3125
3196
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "orion-admin-user-email", children: userEmail })
|
|
3126
3197
|
] }) : null,
|
|
3127
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.
|
|
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
|
+
] })
|
|
3128
3202
|
] })
|
|
3129
3203
|
] }),
|
|
3130
3204
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("main", { className: "orion-admin-main", children })
|
|
@@ -4036,15 +4110,16 @@ function AdminStudioDashboard(rawProps) {
|
|
|
4036
4110
|
}
|
|
4037
4111
|
|
|
4038
4112
|
// src/admin/components/studio/AdminStudioPagesListView.tsx
|
|
4039
|
-
var
|
|
4113
|
+
var import_react19 = require("react");
|
|
4040
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");
|
|
4041
4120
|
var import_ui5 = require("@payloadcms/ui");
|
|
4042
4121
|
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
4043
|
-
var
|
|
4044
|
-
if (!user || typeof user !== "object") return false;
|
|
4045
|
-
const role = user.role;
|
|
4046
|
-
return typeof role === "string" && (role === "admin" || role === "developer");
|
|
4047
|
-
};
|
|
4122
|
+
var pageTemplates = ["standard", "landing", "services", "contact"];
|
|
4048
4123
|
var getPropString3 = (props, key, fallback) => {
|
|
4049
4124
|
if (!props || typeof props !== "object") return fallback;
|
|
4050
4125
|
const direct = props[key];
|
|
@@ -4056,83 +4131,107 @@ var getPropString3 = (props, key, fallback) => {
|
|
|
4056
4131
|
}
|
|
4057
4132
|
return fallback;
|
|
4058
4133
|
};
|
|
4059
|
-
|
|
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) {
|
|
4060
4141
|
const { user } = (0, import_ui5.useAuth)();
|
|
4061
|
-
const pagesCollectionSlug = getPropString3(props, "pagesCollectionSlug", "pages");
|
|
4062
4142
|
const adminBasePath = useAdminBasePath();
|
|
4063
|
-
const
|
|
4064
|
-
const [
|
|
4143
|
+
const pagesCollectionSlug = getPropString3(props, "pagesCollectionSlug", "pages");
|
|
4144
|
+
const [submitting, setSubmitting] = (0, import_react17.useState)(false);
|
|
4065
4145
|
const [error, setError] = (0, import_react17.useState)(null);
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
try {
|
|
4082
|
-
const res = await fetch(apiURL, { credentials: "include" });
|
|
4083
|
-
if (!res.ok) {
|
|
4084
|
-
const body = await res.text();
|
|
4085
|
-
throw new Error(body || "Failed to fetch pages");
|
|
4086
|
-
}
|
|
4087
|
-
const data = await res.json();
|
|
4088
|
-
if (!cancelled) {
|
|
4089
|
-
setDocs(Array.isArray(data.docs) ? data.docs : []);
|
|
4090
|
-
}
|
|
4091
|
-
} catch (err) {
|
|
4092
|
-
if (!cancelled) {
|
|
4093
|
-
setError(err instanceof Error ? err.message : "Failed to fetch pages");
|
|
4094
|
-
}
|
|
4095
|
-
} finally {
|
|
4096
|
-
if (!cancelled) {
|
|
4097
|
-
setLoading(false);
|
|
4098
|
-
}
|
|
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
|
+
] })
|
|
4099
4161
|
}
|
|
4100
|
-
};
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
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)(
|
|
4107
4205
|
AdminPage,
|
|
4108
4206
|
{
|
|
4109
|
-
actions: hasAdminAccess(user) ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_link2.default, { className: "orion-admin-action-button", href: newPagePath, children: "New Page" }) : null,
|
|
4110
4207
|
breadcrumbs: [
|
|
4111
4208
|
{ label: "Dashboard", href: adminBasePath },
|
|
4112
|
-
{ label: "Pages" }
|
|
4209
|
+
{ label: "Pages", href: resolveAdminPath(adminBasePath, "/pages") },
|
|
4210
|
+
{ label: "New Page" }
|
|
4113
4211
|
],
|
|
4114
|
-
description: "
|
|
4115
|
-
title: "
|
|
4116
|
-
children: [
|
|
4117
|
-
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: [
|
|
4118
4215
|
error ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "orion-admin-error", children: error }) : null,
|
|
4119
|
-
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
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
|
+
] })
|
|
4136
4235
|
}
|
|
4137
4236
|
) });
|
|
4138
4237
|
}
|
|
@@ -4141,16 +4240,6 @@ function AdminStudioPagesListView(props) {
|
|
|
4141
4240
|
var import_react18 = require("react");
|
|
4142
4241
|
var import_ui6 = require("@payloadcms/ui");
|
|
4143
4242
|
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
4144
|
-
var hasAdminAccess2 = (user) => {
|
|
4145
|
-
if (!user || typeof user !== "object") return false;
|
|
4146
|
-
const role = user.role;
|
|
4147
|
-
return typeof role === "string" && (role === "admin" || role === "developer");
|
|
4148
|
-
};
|
|
4149
|
-
var isEditor = (user) => {
|
|
4150
|
-
if (!user || typeof user !== "object") return false;
|
|
4151
|
-
const role = user.role;
|
|
4152
|
-
return typeof role === "string" && role === "editor";
|
|
4153
|
-
};
|
|
4154
4243
|
var getPropString4 = (props, key, fallback) => {
|
|
4155
4244
|
if (!props || typeof props !== "object") return fallback;
|
|
4156
4245
|
const direct = props[key];
|
|
@@ -4178,14 +4267,8 @@ var getPageIDFromPathname = (pathname) => {
|
|
|
4178
4267
|
return pagePart ? decodeURIComponent(pagePart) : null;
|
|
4179
4268
|
};
|
|
4180
4269
|
function AdminStudioPageEditView(props) {
|
|
4181
|
-
const { user } = (0, import_ui6.useAuth)();
|
|
4182
4270
|
const adminBasePath = useAdminBasePath();
|
|
4183
4271
|
const iframeRef = (0, import_react18.useRef)(null);
|
|
4184
|
-
const [saving, setSaving] = (0, import_react18.useState)(null);
|
|
4185
|
-
const [dirty, setDirty] = (0, import_react18.useState)(false);
|
|
4186
|
-
const [hasUnpublishedChanges, setHasUnpublishedChanges] = (0, import_react18.useState)(false);
|
|
4187
|
-
const [canUndo, setCanUndo] = (0, import_react18.useState)(false);
|
|
4188
|
-
const [canRedo, setCanRedo] = (0, import_react18.useState)(false);
|
|
4189
4272
|
const builderBasePath = getPropString4(props, "builderBasePath", "/builder");
|
|
4190
4273
|
const pagesPath = resolveAdminPath(adminBasePath, "/pages");
|
|
4191
4274
|
const pageIDFromParams = (0, import_react18.useMemo)(() => getParam(props.params, "id"), [props.params]);
|
|
@@ -4202,96 +4285,6 @@ function AdminStudioPageEditView(props) {
|
|
|
4202
4285
|
}
|
|
4203
4286
|
setDidResolvePathFallback(true);
|
|
4204
4287
|
}, [pageIDFromParams]);
|
|
4205
|
-
const canPublish = hasAdminAccess2(user) || isEditor(user);
|
|
4206
|
-
const refreshUnpublishedState = async (id) => {
|
|
4207
|
-
try {
|
|
4208
|
-
const response = await fetch(
|
|
4209
|
-
`/api/pages/versions?depth=0&limit=25&sort=-updatedAt&where[parent][equals]=${encodeURIComponent(id)}`,
|
|
4210
|
-
{
|
|
4211
|
-
credentials: "include"
|
|
4212
|
-
}
|
|
4213
|
-
);
|
|
4214
|
-
if (!response.ok) {
|
|
4215
|
-
return;
|
|
4216
|
-
}
|
|
4217
|
-
const payload = await response.json();
|
|
4218
|
-
const docs = Array.isArray(payload.docs) ? payload.docs : [];
|
|
4219
|
-
let latestDraft = 0;
|
|
4220
|
-
let latestPublished = 0;
|
|
4221
|
-
docs.forEach((doc) => {
|
|
4222
|
-
const status = doc.version?._status;
|
|
4223
|
-
const millis = typeof doc.updatedAt === "string" ? Date.parse(doc.updatedAt) : Number.NaN;
|
|
4224
|
-
if (!Number.isFinite(millis)) {
|
|
4225
|
-
return;
|
|
4226
|
-
}
|
|
4227
|
-
if (status === "draft") {
|
|
4228
|
-
latestDraft = Math.max(latestDraft, millis);
|
|
4229
|
-
}
|
|
4230
|
-
if (status === "published") {
|
|
4231
|
-
latestPublished = Math.max(latestPublished, millis);
|
|
4232
|
-
}
|
|
4233
|
-
});
|
|
4234
|
-
setHasUnpublishedChanges(latestDraft > 0 && latestDraft >= latestPublished);
|
|
4235
|
-
} catch {
|
|
4236
|
-
}
|
|
4237
|
-
};
|
|
4238
|
-
(0, import_react18.useEffect)(() => {
|
|
4239
|
-
if (!pageID) {
|
|
4240
|
-
return;
|
|
4241
|
-
}
|
|
4242
|
-
void refreshUnpublishedState(pageID);
|
|
4243
|
-
}, [pageID]);
|
|
4244
|
-
const requestSave = (status) => {
|
|
4245
|
-
const iframe = iframeRef.current;
|
|
4246
|
-
if (!iframe?.contentWindow) {
|
|
4247
|
-
import_ui6.toast.error("Editor is not ready yet. Please try again.");
|
|
4248
|
-
return;
|
|
4249
|
-
}
|
|
4250
|
-
setSaving(status);
|
|
4251
|
-
iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type: "save", status }, "*");
|
|
4252
|
-
};
|
|
4253
|
-
const requestHistoryAction = (type) => {
|
|
4254
|
-
const iframe = iframeRef.current;
|
|
4255
|
-
if (!iframe?.contentWindow) {
|
|
4256
|
-
import_ui6.toast.error("Editor is not ready yet. Please try again.");
|
|
4257
|
-
return;
|
|
4258
|
-
}
|
|
4259
|
-
iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type }, "*");
|
|
4260
|
-
};
|
|
4261
|
-
(0, import_react18.useEffect)(() => {
|
|
4262
|
-
const onMessage = (event) => {
|
|
4263
|
-
const data = event.data;
|
|
4264
|
-
if (!data || data.source !== "payload-visual-builder-child" || typeof data.type !== "string") {
|
|
4265
|
-
return;
|
|
4266
|
-
}
|
|
4267
|
-
if (data.type === "dirty-state") {
|
|
4268
|
-
setDirty(Boolean(data.dirty));
|
|
4269
|
-
return;
|
|
4270
|
-
}
|
|
4271
|
-
if (data.type === "history-state") {
|
|
4272
|
-
setCanUndo(Boolean(data.canUndo));
|
|
4273
|
-
setCanRedo(Boolean(data.canRedo));
|
|
4274
|
-
return;
|
|
4275
|
-
}
|
|
4276
|
-
if (data.type === "save-result") {
|
|
4277
|
-
setSaving(null);
|
|
4278
|
-
if (data.ok) {
|
|
4279
|
-
if (data.status === "draft") {
|
|
4280
|
-
setHasUnpublishedChanges(true);
|
|
4281
|
-
} else if (data.status === "published") {
|
|
4282
|
-
setHasUnpublishedChanges(false);
|
|
4283
|
-
} else if (pageID) {
|
|
4284
|
-
void refreshUnpublishedState(pageID);
|
|
4285
|
-
}
|
|
4286
|
-
import_ui6.toast.success(typeof data.message === "string" ? data.message : "Saved.");
|
|
4287
|
-
} else {
|
|
4288
|
-
import_ui6.toast.error(typeof data.message === "string" ? data.message : "Save failed.");
|
|
4289
|
-
}
|
|
4290
|
-
}
|
|
4291
|
-
};
|
|
4292
|
-
window.addEventListener("message", onMessage);
|
|
4293
|
-
return () => window.removeEventListener("message", onMessage);
|
|
4294
|
-
}, []);
|
|
4295
4288
|
if (!pageID && !didResolvePathFallback) {
|
|
4296
4289
|
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
|
|
4297
4290
|
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
@@ -4332,155 +4325,25 @@ function AdminStudioPageEditView(props) {
|
|
|
4332
4325
|
]
|
|
4333
4326
|
}
|
|
4334
4327
|
),
|
|
4335
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
gap: "0.6rem",
|
|
4345
|
-
justifyContent: "space-between",
|
|
4346
|
-
padding: "0.65rem 0.9rem",
|
|
4347
|
-
position: "sticky",
|
|
4348
|
-
top: 0,
|
|
4349
|
-
zIndex: 20
|
|
4350
|
-
},
|
|
4351
|
-
children: [
|
|
4352
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { minWidth: 0 }, children: [
|
|
4353
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { style: { fontWeight: 900 }, children: "Page Editor" }),
|
|
4354
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
4355
|
-
"div",
|
|
4356
|
-
{
|
|
4357
|
-
style: {
|
|
4358
|
-
color: "var(--theme-elevation-600)",
|
|
4359
|
-
fontSize: "0.85rem",
|
|
4360
|
-
overflow: "hidden",
|
|
4361
|
-
textOverflow: "ellipsis"
|
|
4362
|
-
},
|
|
4363
|
-
children: [
|
|
4364
|
-
"Editing: ",
|
|
4365
|
-
pageID
|
|
4366
|
-
]
|
|
4367
|
-
}
|
|
4368
|
-
)
|
|
4369
|
-
] }),
|
|
4370
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { style: { alignItems: "center", display: "flex", gap: "0.5rem" }, children: [
|
|
4371
|
-
/* @__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" }),
|
|
4372
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
4373
|
-
"div",
|
|
4374
|
-
{
|
|
4375
|
-
style: {
|
|
4376
|
-
background: hasUnpublishedChanges ? "#fff3cd" : "var(--theme-success-50)",
|
|
4377
|
-
border: `1px solid ${hasUnpublishedChanges ? "#f0c36d" : "var(--theme-success-300)"}`,
|
|
4378
|
-
borderRadius: 999,
|
|
4379
|
-
color: hasUnpublishedChanges ? "#6a4a00" : "var(--theme-success-700)",
|
|
4380
|
-
fontSize: "0.75rem",
|
|
4381
|
-
fontWeight: 800,
|
|
4382
|
-
padding: "0.2rem 0.55rem",
|
|
4383
|
-
whiteSpace: "nowrap"
|
|
4384
|
-
},
|
|
4385
|
-
title: hasUnpublishedChanges ? "There are saved draft changes not yet published." : "The live page matches the latest published content.",
|
|
4386
|
-
children: hasUnpublishedChanges ? "Unpublished draft changes" : "Live is up to date"
|
|
4387
|
-
}
|
|
4388
|
-
),
|
|
4389
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
4390
|
-
"button",
|
|
4391
|
-
{
|
|
4392
|
-
disabled: !canUndo,
|
|
4393
|
-
onClick: () => requestHistoryAction("undo"),
|
|
4394
|
-
style: {
|
|
4395
|
-
border: "1px solid var(--theme-elevation-300)",
|
|
4396
|
-
borderRadius: 12,
|
|
4397
|
-
cursor: canUndo ? "pointer" : "not-allowed",
|
|
4398
|
-
fontWeight: 800,
|
|
4399
|
-
padding: "0.5rem 0.65rem"
|
|
4400
|
-
},
|
|
4401
|
-
type: "button",
|
|
4402
|
-
children: "Undo"
|
|
4403
|
-
}
|
|
4404
|
-
),
|
|
4405
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
4406
|
-
"button",
|
|
4407
|
-
{
|
|
4408
|
-
disabled: !canRedo,
|
|
4409
|
-
onClick: () => requestHistoryAction("redo"),
|
|
4410
|
-
style: {
|
|
4411
|
-
border: "1px solid var(--theme-elevation-300)",
|
|
4412
|
-
borderRadius: 12,
|
|
4413
|
-
cursor: canRedo ? "pointer" : "not-allowed",
|
|
4414
|
-
fontWeight: 800,
|
|
4415
|
-
padding: "0.5rem 0.65rem"
|
|
4416
|
-
},
|
|
4417
|
-
type: "button",
|
|
4418
|
-
children: "Redo"
|
|
4419
|
-
}
|
|
4420
|
-
),
|
|
4421
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
4422
|
-
"button",
|
|
4423
|
-
{
|
|
4424
|
-
disabled: saving !== null,
|
|
4425
|
-
onClick: () => requestSave("draft"),
|
|
4426
|
-
style: {
|
|
4427
|
-
border: "1px solid var(--theme-elevation-300)",
|
|
4428
|
-
borderRadius: 12,
|
|
4429
|
-
cursor: saving ? "not-allowed" : "pointer",
|
|
4430
|
-
fontWeight: 800,
|
|
4431
|
-
padding: "0.5rem 0.75rem"
|
|
4432
|
-
},
|
|
4433
|
-
type: "button",
|
|
4434
|
-
children: saving === "draft" ? "Saving\u2026" : "Save Draft"
|
|
4435
|
-
}
|
|
4436
|
-
),
|
|
4437
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
4438
|
-
"button",
|
|
4439
|
-
{
|
|
4440
|
-
disabled: !canPublish || saving !== null,
|
|
4441
|
-
onClick: () => requestSave("published"),
|
|
4442
|
-
style: {
|
|
4443
|
-
background: canPublish ? "var(--theme-success-700)" : "var(--theme-elevation-300)",
|
|
4444
|
-
border: "none",
|
|
4445
|
-
borderRadius: 12,
|
|
4446
|
-
color: canPublish ? "var(--theme-elevation-0)" : "var(--theme-elevation-700)",
|
|
4447
|
-
cursor: !canPublish || saving ? "not-allowed" : "pointer",
|
|
4448
|
-
fontWeight: 900,
|
|
4449
|
-
padding: "0.5rem 0.75rem"
|
|
4450
|
-
},
|
|
4451
|
-
type: "button",
|
|
4452
|
-
title: !canPublish ? "You do not have publish permissions." : void 0,
|
|
4453
|
-
children: saving === "published" ? "Publishing\u2026" : "Publish"
|
|
4454
|
-
}
|
|
4455
|
-
)
|
|
4456
|
-
] })
|
|
4457
|
-
]
|
|
4458
|
-
}
|
|
4459
|
-
),
|
|
4460
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
4461
|
-
"iframe",
|
|
4462
|
-
{
|
|
4463
|
-
ref: iframeRef,
|
|
4464
|
-
src: `${builderBasePath.replace(/\/$/, "")}/${pageID}`,
|
|
4465
|
-
style: { border: "none", height: "100%", width: "100%" },
|
|
4466
|
-
title: "Page Builder",
|
|
4467
|
-
onLoad: () => {
|
|
4468
|
-
const iframe = iframeRef.current;
|
|
4469
|
-
if (!iframe?.contentWindow) return;
|
|
4470
|
-
iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type: "dirty-check-request" }, "*");
|
|
4471
|
-
iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type: "history-check-request" }, "*");
|
|
4472
|
-
}
|
|
4473
|
-
}
|
|
4474
|
-
)
|
|
4475
|
-
] })
|
|
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
|
+
) })
|
|
4476
4337
|
] }) });
|
|
4477
4338
|
}
|
|
4478
4339
|
|
|
4479
|
-
// src/admin/components/studio/
|
|
4480
|
-
var import_react19 = require("react");
|
|
4481
|
-
var import_ui7 = require("@payloadcms/ui");
|
|
4340
|
+
// src/admin/components/studio/AdminStudioPagesListView.tsx
|
|
4482
4341
|
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
4483
|
-
var
|
|
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
|
+
};
|
|
4484
4347
|
var getPropString5 = (props, key, fallback) => {
|
|
4485
4348
|
if (!props || typeof props !== "object") return fallback;
|
|
4486
4349
|
const direct = props[key];
|
|
@@ -4492,107 +4355,98 @@ var getPropString5 = (props, key, fallback) => {
|
|
|
4492
4355
|
}
|
|
4493
4356
|
return fallback;
|
|
4494
4357
|
};
|
|
4495
|
-
|
|
4496
|
-
if (!user || typeof user !== "object") return false;
|
|
4497
|
-
const role = user.role;
|
|
4498
|
-
return role === "admin" || role === "developer" || role === "editor";
|
|
4499
|
-
};
|
|
4500
|
-
var slugify = (value) => value.toLowerCase().trim().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-");
|
|
4501
|
-
function AdminStudioNewPageView(props) {
|
|
4502
|
-
const { user } = (0, import_ui7.useAuth)();
|
|
4358
|
+
function AdminStudioPagesListView(props) {
|
|
4503
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)();
|
|
4504
4376
|
const pagesCollectionSlug = getPropString5(props, "pagesCollectionSlug", "pages");
|
|
4505
|
-
const
|
|
4377
|
+
const newPagePath = resolveAdminPath(adminBasePath, "/pages/new");
|
|
4378
|
+
const [loading, setLoading] = (0, import_react19.useState)(true);
|
|
4506
4379
|
const [error, setError] = (0, import_react19.useState)(null);
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
slug,
|
|
4541
|
-
template,
|
|
4542
|
-
title
|
|
4543
|
-
}),
|
|
4544
|
-
credentials: "include",
|
|
4545
|
-
headers: {
|
|
4546
|
-
"Content-Type": "application/json"
|
|
4547
|
-
},
|
|
4548
|
-
method: "POST"
|
|
4549
|
-
});
|
|
4550
|
-
if (!response.ok) {
|
|
4551
|
-
throw new Error(`Failed to create page (${response.status}).`);
|
|
4552
|
-
}
|
|
4553
|
-
const payload = await response.json();
|
|
4554
|
-
const id = typeof payload.id === "string" || typeof payload.id === "number" ? String(payload.id) : "";
|
|
4555
|
-
if (!id) {
|
|
4556
|
-
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
|
+
}
|
|
4557
4413
|
}
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
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)(
|
|
4566
4421
|
AdminPage,
|
|
4567
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,
|
|
4568
4424
|
breadcrumbs: [
|
|
4569
4425
|
{ label: "Dashboard", href: adminBasePath },
|
|
4570
|
-
{ label: "Pages"
|
|
4571
|
-
{ label: "New Page" }
|
|
4426
|
+
{ label: "Pages" }
|
|
4572
4427
|
],
|
|
4573
|
-
description: "
|
|
4574
|
-
title: "
|
|
4575
|
-
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,
|
|
4576
4432
|
error ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "orion-admin-error", children: error }) : null,
|
|
4577
|
-
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("
|
|
4578
|
-
"
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("button", { disabled: submitting, type: "submit", children: submitting ? "Creating..." : "Create Page" })
|
|
4595
|
-
] })
|
|
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
|
+
]
|
|
4596
4450
|
}
|
|
4597
4451
|
) });
|
|
4598
4452
|
}
|
|
@@ -6861,7 +6715,7 @@ function MediaListItem({
|
|
|
6861
6715
|
|
|
6862
6716
|
// src/admin-app/components/MediaUploadForm.tsx
|
|
6863
6717
|
var import_react27 = require("react");
|
|
6864
|
-
var
|
|
6718
|
+
var import_navigation4 = require("next/navigation");
|
|
6865
6719
|
|
|
6866
6720
|
// src/shared/clientImageUploadOptimization.ts
|
|
6867
6721
|
var MAX_DIRECT_UPLOAD_BYTES = 4e6;
|
|
@@ -6996,7 +6850,7 @@ var parseUploadError = async (response) => {
|
|
|
6996
6850
|
return fallback;
|
|
6997
6851
|
};
|
|
6998
6852
|
function MediaUploadForm() {
|
|
6999
|
-
const router = (0,
|
|
6853
|
+
const router = (0, import_navigation4.useRouter)();
|
|
7000
6854
|
const fileInputRef = (0, import_react27.useRef)(null);
|
|
7001
6855
|
const [alt, setAlt] = (0, import_react27.useState)("");
|
|
7002
6856
|
const [file, setFile] = (0, import_react27.useState)(null);
|
|
@@ -7531,17 +7385,17 @@ var FORM_TONE_OVERRIDES = {
|
|
|
7531
7385
|
var IDENTITY_KEYS = /* @__PURE__ */ new Set(["contactEmail", "email", "firstName", "lastName", "name"]);
|
|
7532
7386
|
var RESPONSE_FIELD_PREVIEW_LIMIT = 3;
|
|
7533
7387
|
var RESPONSE_SCROLL_THRESHOLD = 3;
|
|
7534
|
-
var
|
|
7388
|
+
var hasAdminAccess2 = (user) => {
|
|
7535
7389
|
if (!user || typeof user !== "object") return false;
|
|
7536
7390
|
const role = user.role;
|
|
7537
7391
|
return typeof role === "string" && (role === "admin" || role === "developer");
|
|
7538
7392
|
};
|
|
7539
|
-
var
|
|
7393
|
+
var isEditor = (user) => {
|
|
7540
7394
|
if (!user || typeof user !== "object") return false;
|
|
7541
7395
|
const role = user.role;
|
|
7542
7396
|
return typeof role === "string" && role === "editor";
|
|
7543
7397
|
};
|
|
7544
|
-
var canReviewForms2 = (user) =>
|
|
7398
|
+
var canReviewForms2 = (user) => hasAdminAccess2(user) || isEditor(user);
|
|
7545
7399
|
var getPropString13 = (props, key, fallback) => {
|
|
7546
7400
|
if (!props || typeof props !== "object") return fallback;
|
|
7547
7401
|
const direct = props[key];
|
|
@@ -7714,14 +7568,10 @@ function AdminStudioFormsView(props) {
|
|
|
7714
7568
|
"formSubmissionsCollectionSlug",
|
|
7715
7569
|
"form-submissions"
|
|
7716
7570
|
);
|
|
7717
|
-
const formUploadsCollectionSlug = getPropString13(props, "formUploadsCollectionSlug", "form-uploads");
|
|
7718
7571
|
const adminBasePath = useAdminBasePath();
|
|
7719
|
-
const
|
|
7720
|
-
const
|
|
7721
|
-
|
|
7722
|
-
`/collections/${formSubmissionsCollectionSlug}`
|
|
7723
|
-
);
|
|
7724
|
-
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");
|
|
7725
7575
|
const [forms, setForms] = (0, import_react31.useState)([]);
|
|
7726
7576
|
const [submissions, setSubmissions] = (0, import_react31.useState)([]);
|
|
7727
7577
|
const [loading, setLoading] = (0, import_react31.useState)(true);
|
|
@@ -7881,7 +7731,7 @@ function AdminStudioFormsView(props) {
|
|
|
7881
7731
|
import_link3.default,
|
|
7882
7732
|
{
|
|
7883
7733
|
className: "orion-admin-action-button orion-admin-action-button--soft",
|
|
7884
|
-
href: `${
|
|
7734
|
+
href: `${studioFormsPath}/${id}`,
|
|
7885
7735
|
children: "Open Form"
|
|
7886
7736
|
}
|
|
7887
7737
|
)
|
|
@@ -7983,7 +7833,7 @@ function AdminStudioFormsView(props) {
|
|
|
7983
7833
|
import_link3.default,
|
|
7984
7834
|
{
|
|
7985
7835
|
className: "orion-admin-upload-chip",
|
|
7986
|
-
href: `${
|
|
7836
|
+
href: `${studioUploadsPath}/${uploadID}`,
|
|
7987
7837
|
children: uploadLabel
|
|
7988
7838
|
},
|
|
7989
7839
|
uploadID
|
|
@@ -8000,7 +7850,7 @@ function AdminStudioFormsView(props) {
|
|
|
8000
7850
|
import_link3.default,
|
|
8001
7851
|
{
|
|
8002
7852
|
className: "orion-admin-action-button orion-admin-action-button--ghost",
|
|
8003
|
-
href: `${
|
|
7853
|
+
href: `${studioSubmissionsPath}/${submissionID}`,
|
|
8004
7854
|
children: "Open"
|
|
8005
7855
|
}
|
|
8006
7856
|
)
|
|
@@ -8020,53 +7870,1679 @@ function AdminStudioFormsView(props) {
|
|
|
8020
7870
|
) });
|
|
8021
7871
|
}
|
|
8022
7872
|
|
|
8023
|
-
// src/admin/components/studio/
|
|
7873
|
+
// src/admin/components/studio/AdminStudioFormDetailView.tsx
|
|
7874
|
+
var import_link4 = __toESM(require("next/link"));
|
|
8024
7875
|
var import_react32 = require("react");
|
|
8025
|
-
|
|
8026
|
-
|
|
8027
|
-
var
|
|
8028
|
-
|
|
8029
|
-
|
|
8030
|
-
|
|
8031
|
-
|
|
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]
|
|
8032
7914
|
};
|
|
8033
|
-
var
|
|
8034
|
-
|
|
8035
|
-
|
|
8036
|
-
|
|
8037
|
-
const
|
|
8038
|
-
|
|
8039
|
-
const
|
|
8040
|
-
|
|
8041
|
-
|
|
8042
|
-
|
|
8043
|
-
if (!hasAdminAccess4(user)) {
|
|
8044
|
-
return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
8045
|
-
AdminPage,
|
|
8046
|
-
{
|
|
8047
|
-
breadcrumbs: [
|
|
8048
|
-
{ label: "Dashboard", href: adminBasePath },
|
|
8049
|
-
{ label: "Admin Tools" }
|
|
8050
|
-
],
|
|
8051
|
-
description: "You do not have access to this section.",
|
|
8052
|
-
title: "Admin Tools",
|
|
8053
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "orion-admin-card", children: [
|
|
8054
|
-
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: "Access denied" }),
|
|
8055
|
-
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "This section is restricted to administrator and developer accounts." })
|
|
8056
|
-
] })
|
|
8057
|
-
}
|
|
8058
|
-
) });
|
|
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;
|
|
8059
7925
|
}
|
|
8060
|
-
|
|
8061
|
-
|
|
8062
|
-
|
|
8063
|
-
|
|
8064
|
-
|
|
8065
|
-
|
|
8066
|
-
|
|
8067
|
-
|
|
8068
|
-
|
|
8069
|
-
|
|
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",
|
|
9543
|
+
limit: "200",
|
|
9544
|
+
sort: "email"
|
|
9545
|
+
});
|
|
8070
9546
|
const response = await fetch(`/api/users?${params.toString()}`, {
|
|
8071
9547
|
credentials: "include"
|
|
8072
9548
|
});
|
|
@@ -8081,16 +9557,17 @@ function AdminStudioToolsView(props) {
|
|
|
8081
9557
|
setLoading(false);
|
|
8082
9558
|
}
|
|
8083
9559
|
};
|
|
8084
|
-
(0,
|
|
9560
|
+
(0, import_react35.useEffect)(() => {
|
|
8085
9561
|
void loadUsers();
|
|
8086
9562
|
}, []);
|
|
8087
9563
|
const createUser = async (event) => {
|
|
8088
9564
|
event.preventDefault();
|
|
9565
|
+
const form = event.currentTarget;
|
|
8089
9566
|
setCreateSubmitting(true);
|
|
8090
9567
|
setError(null);
|
|
8091
9568
|
setSavedMessage(null);
|
|
8092
9569
|
try {
|
|
8093
|
-
const formData = new FormData(
|
|
9570
|
+
const formData = new FormData(form);
|
|
8094
9571
|
const email = String(formData.get("email") || "").trim();
|
|
8095
9572
|
const password = String(formData.get("password") || "");
|
|
8096
9573
|
const fullName = String(formData.get("fullName") || "").trim();
|
|
@@ -8114,7 +9591,7 @@ function AdminStudioToolsView(props) {
|
|
|
8114
9591
|
if (!response.ok) {
|
|
8115
9592
|
throw new Error(`Failed to create user (${response.status}).`);
|
|
8116
9593
|
}
|
|
8117
|
-
|
|
9594
|
+
form.reset();
|
|
8118
9595
|
await loadUsers();
|
|
8119
9596
|
setSavedMessage("User created.");
|
|
8120
9597
|
} catch (createError) {
|
|
@@ -8152,7 +9629,7 @@ function AdminStudioToolsView(props) {
|
|
|
8152
9629
|
setUpdatingUserID(null);
|
|
8153
9630
|
}
|
|
8154
9631
|
};
|
|
8155
|
-
return /* @__PURE__ */ (0,
|
|
9632
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
|
|
8156
9633
|
AdminPage,
|
|
8157
9634
|
{
|
|
8158
9635
|
breadcrumbs: [
|
|
@@ -8162,53 +9639,44 @@ function AdminStudioToolsView(props) {
|
|
|
8162
9639
|
description: "Manage users and fallback links to Payload native admin.",
|
|
8163
9640
|
title: "Admin Tools",
|
|
8164
9641
|
children: [
|
|
8165
|
-
/* @__PURE__ */ (0,
|
|
8166
|
-
|
|
8167
|
-
|
|
8168
|
-
|
|
8169
|
-
/* @__PURE__ */ (0,
|
|
8170
|
-
/* @__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: [
|
|
8171
9647
|
"Email",
|
|
8172
|
-
/* @__PURE__ */ (0,
|
|
9648
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("input", { name: "email", required: true, type: "email" })
|
|
8173
9649
|
] }),
|
|
8174
|
-
/* @__PURE__ */ (0,
|
|
9650
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("label", { children: [
|
|
8175
9651
|
"Full Name",
|
|
8176
|
-
/* @__PURE__ */ (0,
|
|
9652
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("input", { name: "fullName", type: "text" })
|
|
8177
9653
|
] }),
|
|
8178
|
-
/* @__PURE__ */ (0,
|
|
9654
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("label", { children: [
|
|
8179
9655
|
"Password",
|
|
8180
|
-
/* @__PURE__ */ (0,
|
|
9656
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("input", { name: "password", required: true, type: "password" })
|
|
8181
9657
|
] }),
|
|
8182
|
-
/* @__PURE__ */ (0,
|
|
9658
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("label", { children: [
|
|
8183
9659
|
"Role",
|
|
8184
|
-
/* @__PURE__ */ (0,
|
|
8185
|
-
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: "admin", children: "admin" }),
|
|
8186
|
-
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: "editor", children: "editor" }),
|
|
8187
|
-
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: "client", children: "client" })
|
|
8188
|
-
] })
|
|
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)) })
|
|
8189
9661
|
] }),
|
|
8190
|
-
/* @__PURE__ */ (0,
|
|
9662
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("button", { disabled: createSubmitting, type: "submit", children: createSubmitting ? "Creating..." : "Create User" })
|
|
8191
9663
|
] }),
|
|
8192
|
-
loading ? /* @__PURE__ */ (0,
|
|
8193
|
-
/* @__PURE__ */ (0,
|
|
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) => {
|
|
8194
9666
|
const id = typeof doc.id === "string" || typeof doc.id === "number" ? String(doc.id) : "";
|
|
8195
9667
|
if (!id) return null;
|
|
8196
9668
|
const email = typeof doc.email === "string" ? doc.email : `user-${id}`;
|
|
8197
9669
|
const fullName = typeof doc.fullName === "string" ? doc.fullName : "";
|
|
8198
9670
|
const currentRole = typeof doc.role === "string" ? normalizeRole(doc.role) : "editor";
|
|
8199
|
-
return /* @__PURE__ */ (0,
|
|
8200
|
-
/* @__PURE__ */ (0,
|
|
8201
|
-
/* @__PURE__ */ (0,
|
|
8202
|
-
/* @__PURE__ */ (0,
|
|
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" })
|
|
8203
9675
|
] }),
|
|
8204
|
-
/* @__PURE__ */ (0,
|
|
8205
|
-
/* @__PURE__ */ (0,
|
|
8206
|
-
/* @__PURE__ */ (0,
|
|
8207
|
-
|
|
8208
|
-
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: "editor", children: "editor" }),
|
|
8209
|
-
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: "client", children: "client" })
|
|
8210
|
-
] }),
|
|
8211
|
-
/* @__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" })
|
|
8212
9680
|
] })
|
|
8213
9681
|
] }, id);
|
|
8214
9682
|
}) })
|
|
@@ -8219,14 +9687,14 @@ function AdminStudioToolsView(props) {
|
|
|
8219
9687
|
|
|
8220
9688
|
// src/admin/components/studio/OpenInStudioMenuItem.tsx
|
|
8221
9689
|
var import_ui13 = require("@payloadcms/ui");
|
|
8222
|
-
var
|
|
9690
|
+
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
8223
9691
|
function OpenInStudioMenuItem({ pagesPathBase = "/pages" }) {
|
|
8224
9692
|
const documentInfo = (0, import_ui13.useDocumentInfo)();
|
|
8225
9693
|
const id = documentInfo?.id;
|
|
8226
9694
|
if (!id) {
|
|
8227
9695
|
return null;
|
|
8228
9696
|
}
|
|
8229
|
-
return /* @__PURE__ */ (0,
|
|
9697
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
8230
9698
|
"a",
|
|
8231
9699
|
{
|
|
8232
9700
|
href: `${pagesPathBase}/${id}`,
|
|
@@ -8245,19 +9713,19 @@ function OpenInStudioMenuItem({ pagesPathBase = "/pages" }) {
|
|
|
8245
9713
|
}
|
|
8246
9714
|
|
|
8247
9715
|
// src/admin/components/studio/PageEditRedirectToStudio.tsx
|
|
8248
|
-
var
|
|
9716
|
+
var import_react36 = require("react");
|
|
8249
9717
|
var import_ui14 = require("@payloadcms/ui");
|
|
8250
|
-
var
|
|
9718
|
+
var import_jsx_runtime46 = require("react/jsx-runtime");
|
|
8251
9719
|
function PageEditRedirectToStudio({ pagesPathBase = "/pages" }) {
|
|
8252
9720
|
const documentInfo = (0, import_ui14.useDocumentInfo)();
|
|
8253
9721
|
const id = documentInfo?.id;
|
|
8254
|
-
(0,
|
|
9722
|
+
(0, import_react36.useEffect)(() => {
|
|
8255
9723
|
if (!id) {
|
|
8256
9724
|
return;
|
|
8257
9725
|
}
|
|
8258
9726
|
window.location.replace(`${pagesPathBase}/${id}`);
|
|
8259
9727
|
}, [id, pagesPathBase]);
|
|
8260
|
-
return /* @__PURE__ */ (0,
|
|
9728
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
8261
9729
|
"div",
|
|
8262
9730
|
{
|
|
8263
9731
|
style: {
|
|
@@ -8269,18 +9737,61 @@ function PageEditRedirectToStudio({ pagesPathBase = "/pages" }) {
|
|
|
8269
9737
|
minHeight: "50vh"
|
|
8270
9738
|
},
|
|
8271
9739
|
children: [
|
|
8272
|
-
/* @__PURE__ */ (0,
|
|
8273
|
-
/* @__PURE__ */ (0,
|
|
8274
|
-
id ? /* @__PURE__ */ (0,
|
|
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" })
|
|
8275
9743
|
]
|
|
8276
9744
|
}
|
|
8277
9745
|
);
|
|
8278
9746
|
}
|
|
8279
9747
|
|
|
8280
|
-
// src/admin/components/studio/
|
|
8281
|
-
var
|
|
9748
|
+
// src/admin/components/studio/StudioDocumentRedirect.tsx
|
|
9749
|
+
var import_react37 = require("react");
|
|
8282
9750
|
var import_ui15 = require("@payloadcms/ui");
|
|
8283
|
-
var
|
|
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");
|
|
8284
9795
|
var toTitle = (slug) => slug.split("-").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
8285
9796
|
var buildNav = (pathname, adminBasePath) => {
|
|
8286
9797
|
if (pathname.includes("/globals/")) {
|
|
@@ -8325,8 +9836,8 @@ var buildNav = (pathname, adminBasePath) => {
|
|
|
8325
9836
|
};
|
|
8326
9837
|
function StudioBackBreadcrumb() {
|
|
8327
9838
|
const adminBasePath = useAdminBasePath();
|
|
8328
|
-
const [pathname, setPathname] = (0,
|
|
8329
|
-
(0,
|
|
9839
|
+
const [pathname, setPathname] = (0, import_react38.useState)("");
|
|
9840
|
+
(0, import_react38.useEffect)(() => {
|
|
8330
9841
|
const update = () => setPathname(window.location.pathname);
|
|
8331
9842
|
update();
|
|
8332
9843
|
window.addEventListener("popstate", update);
|
|
@@ -8334,13 +9845,13 @@ function StudioBackBreadcrumb() {
|
|
|
8334
9845
|
}, []);
|
|
8335
9846
|
const nav = buildNav(pathname, adminBasePath);
|
|
8336
9847
|
if (!nav) return null;
|
|
8337
|
-
return /* @__PURE__ */ (0,
|
|
9848
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_ui16.SetStepNav, { nav });
|
|
8338
9849
|
}
|
|
8339
9850
|
|
|
8340
9851
|
// src/admin/components/studio/StudioContactFormRedirect.tsx
|
|
8341
|
-
var
|
|
8342
|
-
var
|
|
8343
|
-
var
|
|
9852
|
+
var import_react39 = require("react");
|
|
9853
|
+
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
9854
|
+
var getPropString15 = (props, key, fallback) => {
|
|
8344
9855
|
if (!props || typeof props !== "object") return fallback;
|
|
8345
9856
|
const direct = props[key];
|
|
8346
9857
|
if (typeof direct === "string" && direct.length > 0) return direct;
|
|
@@ -8353,13 +9864,13 @@ var getPropString14 = (props, key, fallback) => {
|
|
|
8353
9864
|
};
|
|
8354
9865
|
function StudioContactFormRedirect(props) {
|
|
8355
9866
|
const adminBasePath = useAdminBasePath();
|
|
8356
|
-
const studioContactFormPath =
|
|
9867
|
+
const studioContactFormPath = getPropString15(props, "studioContactFormPath", "/contact-form");
|
|
8357
9868
|
const targetPath = resolveAdminPath(adminBasePath, studioContactFormPath);
|
|
8358
|
-
(0,
|
|
9869
|
+
(0, import_react39.useEffect)(() => {
|
|
8359
9870
|
if (window.location.pathname === targetPath) return;
|
|
8360
9871
|
window.location.replace(targetPath);
|
|
8361
9872
|
}, [targetPath]);
|
|
8362
|
-
return /* @__PURE__ */ (0,
|
|
9873
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
|
|
8363
9874
|
"div",
|
|
8364
9875
|
{
|
|
8365
9876
|
style: {
|
|
@@ -8372,8 +9883,8 @@ function StudioContactFormRedirect(props) {
|
|
|
8372
9883
|
minHeight: "40vh"
|
|
8373
9884
|
},
|
|
8374
9885
|
children: [
|
|
8375
|
-
/* @__PURE__ */ (0,
|
|
8376
|
-
/* @__PURE__ */ (0,
|
|
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" })
|
|
8377
9888
|
]
|
|
8378
9889
|
}
|
|
8379
9890
|
);
|
|
@@ -8385,6 +9896,9 @@ function StudioContactFormRedirect(props) {
|
|
|
8385
9896
|
AdminStudioContactFormView,
|
|
8386
9897
|
AdminStudioDashboard,
|
|
8387
9898
|
AdminStudioFooterGlobalView,
|
|
9899
|
+
AdminStudioFormDetailView,
|
|
9900
|
+
AdminStudioFormSubmissionView,
|
|
9901
|
+
AdminStudioFormUploadView,
|
|
8388
9902
|
AdminStudioFormsView,
|
|
8389
9903
|
AdminStudioGlobalsView,
|
|
8390
9904
|
AdminStudioHeaderGlobalView,
|
|
@@ -8410,6 +9924,7 @@ function StudioContactFormRedirect(props) {
|
|
|
8410
9924
|
StatusBadge,
|
|
8411
9925
|
StudioBackBreadcrumb,
|
|
8412
9926
|
StudioContactFormRedirect,
|
|
9927
|
+
StudioDocumentRedirect,
|
|
8413
9928
|
StudioSectionLayout,
|
|
8414
9929
|
ThemeProvider,
|
|
8415
9930
|
ThemeSwitcher,
|