From d3605b0149fa787206ec337ae5e34b0c609a8dc0 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 12 Mar 2026 09:54:08 -0700 Subject: [PATCH] update client validation/pages --- client/src/Hooks/useSettingsForm.ts | 4 ++-- client/src/Pages/Settings/index.tsx | 19 +++---------------- client/src/Validation/settings.ts | 16 ++++++++-------- 3 files changed, 13 insertions(+), 26 deletions(-) diff --git a/client/src/Hooks/useSettingsForm.ts b/client/src/Hooks/useSettingsForm.ts index 3af8c229e..4b0768d79 100644 --- a/client/src/Hooks/useSettingsForm.ts +++ b/client/src/Hooks/useSettingsForm.ts @@ -1,14 +1,14 @@ import { useMemo } from "react"; import { settingsSchema } from "@/Validation/settings"; import type { Settings } from "@/Types/Settings"; -import type { SettingsFormData } from "@/Validation/settings"; +import type { SettingsFormInput } from "@/Validation/settings"; interface UseSettingsFormOptions { data?: Settings | null; } export const useSettingsForm = ({ data = null }: UseSettingsFormOptions = {}) => { return useMemo(() => { - const defaults: SettingsFormData = { + const defaults: SettingsFormInput = { systemEmailIgnoreTLS: data?.systemEmailIgnoreTLS ?? false, systemEmailRequireTLS: data?.systemEmailRequireTLS ?? false, systemEmailRejectUnauthorized: data?.systemEmailRejectUnauthorized ?? true, diff --git a/client/src/Pages/Settings/index.tsx b/client/src/Pages/Settings/index.tsx index e51255157..302ce9ab2 100644 --- a/client/src/Pages/Settings/index.tsx +++ b/client/src/Pages/Settings/index.tsx @@ -20,7 +20,7 @@ import { useGet, usePatch, usePost, useLazyGet } from "@/Hooks/UseApi"; import { useToast } from "@/Hooks/UseToast"; import { useSettingsForm } from "@/Hooks/useSettingsForm"; import { useIsAdmin } from "@/Hooks/useIsAdmin.js"; -import type { SettingsFormData } from "@/Validation/settings"; +import type { SettingsFormData, SettingsFormInput } from "@/Validation/settings"; import { useState } from "react"; import { Controller } from "react-hook-form"; import { TextField, Button, FieldLabel, SliderWithLabel } from "@/Components/inputs"; @@ -89,7 +89,7 @@ export const SettingsPage = () => { // Initialize form with schema and defaults const { schema, defaults } = useSettingsForm({ data: fetchedSettings?.settings }); - const form = useForm({ + const form = useForm({ resolver: zodResolver(schema), defaultValues: defaults, mode: "onChange", @@ -256,20 +256,7 @@ export const SettingsPage = () => { delete (dataToSend as any).systemEmailPassword; } - // Convert undefined to empty string for backend unsetting - const processedData = Object.entries(dataToSend).reduce((acc, [key, value]) => { - const typedKey = key as keyof SettingsFormData; - if (value === undefined) { - (acc as any)[typedKey] = ""; - } else if (typeof value === "object" && value !== null) { - (acc as any)[typedKey] = value; - } else { - (acc as any)[typedKey] = value; - } - return acc; - }, {} as Partial); - - const result = await patch("/settings", processedData as SettingsFormData); + const result = await patch("/settings", dataToSend as SettingsFormData); if (result?.success) { // Update API key state from response diff --git a/client/src/Validation/settings.ts b/client/src/Validation/settings.ts index 975927d1c..cf122f69d 100644 --- a/client/src/Validation/settings.ts +++ b/client/src/Validation/settings.ts @@ -7,7 +7,7 @@ export const settingsSchema = z.object({ systemEmailRejectUnauthorized: z.boolean(), systemEmailConnectionHost: z .string() - .transform((val) => (val.trim() === "" ? undefined : val.trim())) + .transform((val) => (val.trim() === "" ? null : val.trim())) .optional(), systemEmailSecure: z.boolean().optional(), systemEmailPool: z.boolean().optional(), @@ -19,31 +19,30 @@ export const settingsSchema = z.object({ .max(CHECK_TTL_SENTINEL, `Maximum ${CHECK_TTL_SENTINEL}`), pagespeedApiKey: z .string() - .transform((val) => (val.trim() === "" ? undefined : val.trim())) + .transform((val) => (val.trim() === "" ? null : val.trim())) .optional(), systemEmailHost: z .string() .regex(/^[a-zA-Z0-9.-]*$/, "Invalid hostname or IP address") - .transform((val) => (val.trim() === "" ? undefined : val.trim())) + .transform((val) => (val.trim() === "" ? null : val.trim())) .optional(), systemEmailPort: z.number().int().min(1).max(65535).optional(), systemEmailAddress: z - .string() .email("Please enter a valid email address") .or(z.literal("")) - .transform((val) => (val === "" ? undefined : val.toLowerCase().trim())) + .transform((val) => (val === "" ? null : val.toLowerCase().trim())) .optional(), systemEmailUser: z .string() - .transform((val) => (val.trim() === "" ? undefined : val.trim())) + .transform((val) => (val.trim() === "" ? null : val.trim())) .optional(), systemEmailPassword: z .string() - .transform((val) => (val.trim() === "" ? undefined : val.trim())) + .transform((val) => (val.trim() === "" ? null : val.trim())) .optional(), systemEmailTLSServername: z .string() - .transform((val) => (val.trim() === "" ? undefined : val.trim())) + .transform((val) => (val.trim() === "" ? null : val.trim())) .optional(), globalThresholds: z.object({ cpu: z.number().int().min(1).max(100), @@ -53,4 +52,5 @@ export const settingsSchema = z.object({ }), }); +export type SettingsFormInput = z.input; export type SettingsFormData = z.infer;