diff --git a/app/root/portfolio/actions.ts b/app/root/portfolio/actions.ts
index 3bd287f..ca1f49a 100644
--- a/app/root/portfolio/actions.ts
+++ b/app/root/portfolio/actions.ts
@@ -14,6 +14,7 @@ import { getLocalizedPath } from "@/lib/locale";
import { removeManagedMediaFile } from "@/lib/media-storage";
import { mediaFieldInputSchema } from "@/lib/media-validation";
import { prisma } from "@/lib/prisma";
+import { isCheckedFormValue } from "@/lib/form-data";
import {
assetInputSchema,
categoryInputSchema,
@@ -40,7 +41,7 @@ function withMessage(pathname: string, type: "success" | "error", message: strin
}
function normalizeCheckboxValue(formData: FormData, key: string) {
- return formData.get(key) === "on";
+ return isCheckedFormValue(formData.get(key));
}
function parseJsonArray(rawValue: FormDataEntryValue | null, key: string) {
diff --git a/app/root/portfolio/projects/[id]/page.tsx b/app/root/portfolio/projects/[id]/page.tsx
index 9b2901f..de2bfcb 100644
--- a/app/root/portfolio/projects/[id]/page.tsx
+++ b/app/root/portfolio/projects/[id]/page.tsx
@@ -78,6 +78,8 @@ export default async function RootPortfolioProjectPage({
logoutAction={logoutAction}
headerTitle={copy.title}
headerDescription={copy.subtitle}
+ saveFormId="portfolio-project-form"
+ saveButtonLabel={copy.saveProject}
>
{searchParams?.success ? (
@@ -100,7 +102,6 @@ export default async function RootPortfolioProjectPage({
project={project}
formId="portfolio-project-form"
redirectPath={`/root/portfolio/projects/${project.id}`}
- submitLabel={copy.saveProject}
/>
diff --git a/app/root/portfolio/projects/new/page.tsx b/app/root/portfolio/projects/new/page.tsx
index 535442a..980c2e0 100644
--- a/app/root/portfolio/projects/new/page.tsx
+++ b/app/root/portfolio/projects/new/page.tsx
@@ -58,6 +58,7 @@ export default async function RootNewPortfolioProjectPage({
logoutAction={logoutAction}
headerTitle={copy.title}
headerDescription={copy.subtitle}
+ saveFormId="portfolio-project-form"
>
{searchParams?.error ? (
@@ -73,7 +74,6 @@ export default async function RootNewPortfolioProjectPage({
mediaOptions={mediaOptions}
formId="portfolio-project-form"
redirectPath="/root/portfolio/projects/new"
- submitLabel="Projekt anlegen"
/>
diff --git a/app/root/smtp/actions.ts b/app/root/smtp/actions.ts
index ac65266..4de36ed 100644
--- a/app/root/smtp/actions.ts
+++ b/app/root/smtp/actions.ts
@@ -5,6 +5,7 @@ import { redirect } from "next/navigation";
import { isRedirectError } from "next/dist/client/components/redirect";
import { clearAdminSessionCookie, isAdminAuthenticated } from "@/lib/admin-auth";
+import { isCheckedFormValue } from "@/lib/form-data";
import {
getMailSettings,
updateMailSettings,
@@ -53,7 +54,7 @@ function parseMailSettingsFormData(
smtp: {
host,
port: parsePort(portValue || String(existingSettings.smtp.port)),
- secure: formData.get("smtpSecure") === "on",
+ secure: isCheckedFormValue(formData.get("smtpSecure")),
username,
password: password.trim() ? password : existingSettings.smtp.password,
},
diff --git a/app/root/smtp/contact-protection/actions.ts b/app/root/smtp/contact-protection/actions.ts
index 2e34ab8..66d5b9c 100644
--- a/app/root/smtp/contact-protection/actions.ts
+++ b/app/root/smtp/contact-protection/actions.ts
@@ -5,6 +5,7 @@ import { redirect } from "next/navigation";
import { isRedirectError } from "next/dist/client/components/redirect";
import { clearAdminSessionCookie, isAdminAuthenticated } from "@/lib/admin-auth";
+import { isCheckedFormValue } from "@/lib/form-data";
import {
getContactProtectionSettings,
updateContactProtectionSettings,
@@ -39,10 +40,10 @@ function parseContactProtectionFormData(
formData: FormData,
existingSettings: ContactProtectionSettings,
): ContactProtectionSettings {
- const turnstileEnabled = formData.get("turnstileEnabled") === "on";
+ const turnstileEnabled = isCheckedFormValue(formData.get("turnstileEnabled"));
const turnstileSiteKey = String(formData.get("turnstileSiteKey") ?? "").trim();
const turnstileSecretKey = String(formData.get("turnstileSecretKey") ?? "");
- const rateLimitEnabled = formData.get("contactRateLimitEnabled") === "on";
+ const rateLimitEnabled = isCheckedFormValue(formData.get("contactRateLimitEnabled"));
if (turnstileEnabled && !turnstileSiteKey) {
throw new Error("Turnstile site key is required when Turnstile is enabled.");
diff --git a/components/root/form-save-button.tsx b/components/root/form-save-button.tsx
index a84e1df..aa70513 100644
--- a/components/root/form-save-button.tsx
+++ b/components/root/form-save-button.tsx
@@ -39,7 +39,9 @@ export function FormSaveButton({
const [isDirty, setIsDirty] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false);
const baselineRef = useRef
-
-