diff --git a/client/src/Hooks/useSettingsForm.ts b/client/src/Hooks/useSettingsForm.ts new file mode 100644 index 000000000..17a67af25 --- /dev/null +++ b/client/src/Hooks/useSettingsForm.ts @@ -0,0 +1,37 @@ +import { useMemo } from "react"; +import { settingsSchema } from "@/Validation/settings"; +import type { Settings } from "@/Types/Settings"; +import type { SettingsFormData } from "@/Validation/settings"; + +interface UseSettingsFormOptions { + data?: Settings | null; +} +export const useSettingsForm = ({ data = null }: UseSettingsFormOptions = {}) => { + return useMemo(() => { + const defaults: SettingsFormData = { + systemEmailIgnoreTLS: data?.systemEmailIgnoreTLS || false, + systemEmailRequireTLS: data?.systemEmailRequireTLS || false, + systemEmailRejectUnauthorized: data?.systemEmailRejectUnauthorized || true, + systemEmailSecure: data?.systemEmailSecure || false, + systemEmailPool: data?.systemEmailPool || false, + showURL: data?.showURL || false, + systemEmailHost: data?.systemEmailHost || "", + systemEmailUser: data?.systemEmailUser || "", + systemEmailAddress: data?.systemEmailAddress || "", + systemEmailConnectionHost: data?.systemEmailConnectionHost || "localhost", + systemEmailTLSServername: data?.systemEmailTLSServername || "", + systemEmailPort: data?.systemEmailPort || "", + globalThresholds: { + cpu: data?.globalThresholds?.cpu || "", + memory: data?.globalThresholds?.memory || "", + disk: data?.globalThresholds?.disk || "", + temperature: data?.globalThresholds?.temperature || "", + }, + checkTTL: data?.checkTTL || 30, + pagespeedApiKey: "", + systemEmailPassword: "", + }; + + return { schema: settingsSchema, defaults }; + }, [data]); +}; diff --git a/client/src/Pages/Settings/SettingsAbout.jsx b/client/src/Pages/Settings/SettingsAbout.jsx index 6a8125af3..7b0a4ad2c 100644 --- a/client/src/Pages/Settings/SettingsAbout.jsx +++ b/client/src/Pages/Settings/SettingsAbout.jsx @@ -16,7 +16,7 @@ const SettingsAbout = () => { component="h1" variant="h2" > - {t("settingsPage.aboutSettings.title")} + {t("pages.settings.aboutSettings.title")} @@ -24,7 +24,7 @@ const SettingsAbout = () => { {t("common.appName")} {__APP_VERSION__} - {t("settingsPage.aboutSettings.labelDevelopedBy")} + {t("pages.settings.aboutSettings.labelDevelopedBy")} { +const SettingsDemoMonitors = ({ isAdmin, HEADER_SX, isLoading }) => { const { t } = useTranslation(); const theme = useTheme(); // Local state @@ -18,7 +19,8 @@ const SettingsDemoMonitors = ({ isAdmin, HEADER_SX, handleChange, isLoading }) = if (!isAdmin) { return null; } - + const { post: postDemoMonitors } = usePost(); + const { deleteFn: deleteAllMonitorsFn } = useDelete(); return ( <> @@ -27,10 +29,10 @@ const SettingsDemoMonitors = ({ isAdmin, HEADER_SX, handleChange, isLoading }) = component="h1" variant="h2" > - {t("settingsPage.demoMonitorsSettings.title")} + {t("pages.settings.demoMonitorsSettings.title")} - {t("settingsPage.demoMonitorsSettings.description")} + {t("pages.settings.demoMonitorsSettings.description")} @@ -38,17 +40,12 @@ const SettingsDemoMonitors = ({ isAdmin, HEADER_SX, handleChange, isLoading }) = variant="contained" color="accent" loading={isLoading} - onClick={() => { - const syntheticEvent = { - target: { - name: "demo", - }, - }; - handleChange(syntheticEvent); + onClick={async () => { + await postDemoMonitors("/monitors/demo", {}); }} sx={{ mt: theme.spacing(4) }} > - {t("settingsPage.demoMonitorsSettings.buttonAddMonitors")} + {t("pages.settings.demoMonitorsSettings.buttonAddMonitors")} @@ -58,10 +55,10 @@ const SettingsDemoMonitors = ({ isAdmin, HEADER_SX, handleChange, isLoading }) = component="h1" variant="h2" > - {t("settingsPage.systemResetSettings.title")} + {t("pages.settings.systemResetSettings.title")} - {t("settingsPage.systemResetSettings.description")} + {t("pages.settings.systemResetSettings.description")} @@ -72,22 +69,17 @@ const SettingsDemoMonitors = ({ isAdmin, HEADER_SX, handleChange, isLoading }) = onClick={() => setIsOpen(true)} sx={{ mt: theme.spacing(4) }} > - {t("settingsPage.systemResetSettings.buttonRemoveAllMonitors")} + {t("pages.settings.systemResetSettings.buttonRemoveAllMonitors")} setIsOpen(false)} - confirmationButtonLabel={t("settingsPage.systemResetSettings.dialogConfirm")} - onConfirm={() => { - const syntheticEvent = { - target: { - name: "deleteMonitors", - }, - }; - handleChange(syntheticEvent); + confirmationButtonLabel={t("pages.settings.systemResetSettings.dialogConfirm")} + onConfirm={async () => { + await deleteAllMonitorsFn("/monitors/"); setIsOpen(false); }} isLoading={isLoading} @@ -99,7 +91,6 @@ const SettingsDemoMonitors = ({ isAdmin, HEADER_SX, handleChange, isLoading }) = SettingsDemoMonitors.propTypes = { isAdmin: PropTypes.bool, - handleChange: PropTypes.func, HEADER_SX: PropTypes.object, }; diff --git a/client/src/Pages/Settings/SettingsEmail.jsx b/client/src/Pages/Settings/SettingsEmail.jsx index f31373ed9..180b7f2d9 100644 --- a/client/src/Pages/Settings/SettingsEmail.jsx +++ b/client/src/Pages/Settings/SettingsEmail.jsx @@ -15,16 +15,18 @@ import { PasswordEndAdornment } from "@/Components/v1/Inputs/TextInput/Adornment import { usePost } from "@/Hooks/UseApi"; import { useSelector } from "react-redux"; import { createToast } from "@/Utils/toastUtils.jsx"; +import { Controller } from "react-hook-form"; const SettingsEmail = ({ isAdmin, HEADER_SX, - handleChange, - settingsData, - setSettingsData, isEmailPasswordSet, emailPasswordHasBeenReset, setEmailPasswordHasBeenReset, + control, + defaults, + formValues, + setValue, }) => { // Setup const { t } = useTranslation(); @@ -44,22 +46,13 @@ const SettingsEmail = ({ systemEmailIgnoreTLS = false, systemEmailRequireTLS = false, systemEmailRejectUnauthorized = true, - } = settingsData?.settings || {}; - // Local state - const [password, setPassword] = useState(""); + } = formValues || {}; // Network const { post: sendTestEmailFn, loading: isSending } = usePost(); const user = useSelector((state) => state.auth.user); // Handlers - const handlePasswordChange = (e) => { - setPassword(e.target.value); - setSettingsData({ - ...settingsData, - settings: { ...settingsData.settings, systemEmailPassword: e.target.value }, - }); - }; /** * Handle sending test email with current form values @@ -70,10 +63,10 @@ const SettingsEmail = ({ !systemEmailHost || !systemEmailPort || !systemEmailAddress || - !(password || systemEmailPassword) + !systemEmailPassword ) { createToast({ - body: t("settingsPage.emailSettings.toastEmailRequiredFieldsError"), + body: t("pages.settings.emailSettings.toastEmailRequiredFieldsError"), variant: "error", }); return; @@ -85,7 +78,7 @@ const SettingsEmail = ({ systemEmailHost, systemEmailPort, systemEmailAddress, - systemEmailPassword: password || systemEmailPassword, + systemEmailPassword, systemEmailSecure, systemEmailPool, systemEmailIgnoreTLS, @@ -108,229 +101,267 @@ const SettingsEmail = ({ component="h1" variant="h2" > - {t("settingsPage.emailSettings.title")} + {t("pages.settings.emailSettings.title")} - {t("settingsPage.emailSettings.description")} + {t("pages.settings.emailSettings.description")} - - - - - - - - - - - - - - - {(isEmailPasswordSet === false || emailPasswordHasBeenReset === true) && ( - - } - /> - - )} - {isEmailPasswordSet === true && emailPasswordHasBeenReset === false && ( - - {t("settingsPage.emailSettings.labelPasswordSet")} - - - )} + + + ( + + )} + /> + + + ( + + )} + /> + + + ( + + )} + /> + + + ( + + )} + /> + + {(isEmailPasswordSet === false || emailPasswordHasBeenReset === true) && ( - ( + } + error={!!fieldState.error} + helperText={fieldState.error?.message} + /> + )} /> + )} + + {isEmailPasswordSet === true && emailPasswordHasBeenReset === false && ( - + {t("pages.settings.emailSettings.labelPasswordSet")} + + )} + + ( + + )} + /> + + + ( + + )} + /> + + + {[ + [ + "pages.settings.emailSettings.labelSecure", + "systemEmailSecure", + systemEmailSecure, + ], + [ + "pages.settings.emailSettings.labelPool", + "systemEmailPool", + systemEmailPool, + ], + [ + "pages.settings.emailSettings.labelIgnoreTLS", + "systemEmailIgnoreTLS", + systemEmailIgnoreTLS, + ], + [ + "pages.settings.emailSettings.labelRequireTLS", + "systemEmailRequireTLS", + systemEmailRequireTLS, + ], + [ + "pages.settings.emailSettings.labelRejectUnauthorized", + "systemEmailRejectUnauthorized", + systemEmailRejectUnauthorized, + ], + ].map(([labelKey, name, value]) => ( + ( + + {t(labelKey)} + + + + )} + /> + ))} + + - {[ - [ - "settingsPage.emailSettings.labelSecure", - "systemEmailSecure", - systemEmailSecure, - ], - [ - "settingsPage.emailSettings.labelPool", - "systemEmailPool", - systemEmailPool, - ], - [ - "settingsPage.emailSettings.labelIgnoreTLS", - "systemEmailIgnoreTLS", - systemEmailIgnoreTLS, - ], - [ - "settingsPage.emailSettings.labelRequireTLS", - "systemEmailRequireTLS", - systemEmailRequireTLS, - ], - [ - "settingsPage.emailSettings.labelRejectUnauthorized", - "systemEmailRejectUnauthorized", - systemEmailRejectUnauthorized, - ], - ].map(([labelKey, name, value]) => ( - - {t(labelKey)} - - - ))} - - - - - {JSON.stringify( - { - host: systemEmailHost, - port: systemEmailPort, - secure: systemEmailSecure, - auth: { - user: systemEmailUser || systemEmailAddress, - pass: "", - }, - name: systemEmailConnectionHost || "localhost", - pool: systemEmailPool, - tls: { - rejectUnauthorized: systemEmailRejectUnauthorized, - ignoreTLS: systemEmailIgnoreTLS, - requireTLS: systemEmailRequireTLS, - servername: systemEmailTLSServername, - }, + + {JSON.stringify( + { + host: systemEmailHost, + port: systemEmailPort, + secure: systemEmailSecure, + auth: { + user: systemEmailUser || systemEmailAddress, + pass: "", }, - null, - 2 - )} - - - - -
-						{JSON.stringify({
-							systemEmailHost,
-							systemEmailAddress,
-							systemEmailPassword,
-						})}
-					
- - - {systemEmailHost && - systemEmailPort && - systemEmailAddress && - systemEmailPassword && ( - + name: systemEmailConnectionHost || "localhost", + pool: systemEmailPool, + tls: { + rejectUnauthorized: systemEmailRejectUnauthorized, + ignoreTLS: systemEmailIgnoreTLS, + requireTLS: systemEmailRequireTLS, + servername: systemEmailTLSServername, + }, + }, + null, + 2 )} +
-
-
+ + + + {systemEmailHost && + systemEmailPort && + systemEmailAddress && + systemEmailPassword && ( + + )} + + ); }; SettingsEmail.propTypes = { isAdmin: PropTypes.bool, - settingsData: PropTypes.object, - setSettingsData: PropTypes.func, - handleChange: PropTypes.func, HEADER_SX: PropTypes.object, isPasswordSet: PropTypes.bool, }; diff --git a/client/src/Pages/Settings/SettingsExport.jsx b/client/src/Pages/Settings/SettingsExport.jsx index fe04697f4..b289592d1 100644 --- a/client/src/Pages/Settings/SettingsExport.jsx +++ b/client/src/Pages/Settings/SettingsExport.jsx @@ -8,8 +8,9 @@ import { PropTypes } from "prop-types"; import { useTranslation } from "react-i18next"; import Dialog from "@/Components/v1/Dialog/index.jsx"; import { useState } from "react"; +import { useLazyGet } from "@/Hooks/UseApi"; -const SettingsDemoMonitors = ({ isAdmin, HEADER_SX, handleChange, isLoading }) => { +const SettingsDemoMonitors = ({ isAdmin, HEADER_SX, isLoading }) => { const { t } = useTranslation(); const theme = useTheme(); // Local state @@ -18,6 +19,29 @@ const SettingsDemoMonitors = ({ isAdmin, HEADER_SX, handleChange, isLoading }) = if (!isAdmin) { return null; } + const { get: fetchJson } = useLazyGet(); + + const handleExport = async () => { + const res = await fetchJson("/monitors/export/json"); + const json = res?.data ?? []; + if (!json || json.length === 0) { + return; + } + + const blob = new Blob([JSON.stringify(json, null, 2)], { + type: "application/json", + }); + const url = URL.createObjectURL(blob); + + const link = document.createElement("a"); + link.href = url; + link.download = "monitors.json"; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + URL.revokeObjectURL(url); + return; + }; return ( <> @@ -38,14 +62,7 @@ const SettingsDemoMonitors = ({ isAdmin, HEADER_SX, handleChange, isLoading }) = variant="contained" color="accent" loading={isLoading} - onClick={() => { - const syntheticEvent = { - target: { - name: "export", - }, - }; - handleChange(syntheticEvent); - }} + onClick={handleExport} sx={{ mt: theme.spacing(4) }} > Export Monitors to JSON @@ -58,7 +75,6 @@ const SettingsDemoMonitors = ({ isAdmin, HEADER_SX, handleChange, isLoading }) = SettingsDemoMonitors.propTypes = { isAdmin: PropTypes.bool, - handleChange: PropTypes.func, HEADER_SX: PropTypes.object, }; diff --git a/client/src/Pages/Settings/SettingsGlobalThresholds.jsx b/client/src/Pages/Settings/SettingsGlobalThresholds.jsx index ea58478e2..c2bc671f1 100644 --- a/client/src/Pages/Settings/SettingsGlobalThresholds.jsx +++ b/client/src/Pages/Settings/SettingsGlobalThresholds.jsx @@ -7,39 +7,18 @@ import TextInput from "@/Components/v1/Inputs/TextInput/index.jsx"; import { useTheme } from "@emotion/react"; import { PropTypes } from "prop-types"; import { useTranslation } from "react-i18next"; +import { Controller } from "react-hook-form"; const SettingsGlobalThresholds = ({ isAdmin, HEADING_SX, - settingsData, - setSettingsData, + + control, + defaults, }) => { const { t } = useTranslation(); // For language translation const theme = useTheme(); // MUI theme access - // Handles input change and updates parent state - const handleChange = (e, min, max) => { - const { name, value } = e.target; - - const numValue = parseFloat(value); - const isValidNumber = - value === "" || - (!isNaN(numValue) && isFinite(numValue) && numValue >= min && numValue <= max); - - if (isValidNumber) { - setSettingsData((prev) => ({ - ...prev, - settings: { - ...prev.settings, - globalThresholds: { - ...prev.settings?.globalThresholds, - [name]: value, - }, - }, - })); - } - }; - // Only render this section for admins if (!isAdmin) return null; @@ -51,11 +30,11 @@ const SettingsGlobalThresholds = ({ component="h1" variant="h2" > - {t("settingsPage.globalThresholds.title", "Global Thresholds")} + {t("pages.settings.globalThresholds.title", "Global Thresholds")} {t( - "settingsPage.globalThresholds.description", + "pages.settings.globalThresholds.description", "Configure global CPU, Memory, Disk, and Temperature thresholds." )} @@ -69,14 +48,21 @@ const SettingsGlobalThresholds = ({ ["Disk Threshold (%)", "disk", 1, 100], ["Temperature Threshold (°C)", "temperature", 1, 150], ].map(([label, name, min, max]) => ( - handleChange(e, min, max)} + name={`globalThresholds.${name}`} + control={control} + defaultValue={defaults.globalThresholds?.[name]} + render={({ field, fieldState }) => ( + + )} /> ))} @@ -88,8 +74,6 @@ const SettingsGlobalThresholds = ({ SettingsGlobalThresholds.propTypes = { isAdmin: PropTypes.bool, HEADING_SX: PropTypes.object, - settingsData: PropTypes.object, - setSettingsData: PropTypes.func, }; export default SettingsGlobalThresholds; diff --git a/client/src/Pages/Settings/SettingsPagespeed.jsx b/client/src/Pages/Settings/SettingsPagespeed.jsx index b0d5d6441..a479ff660 100644 --- a/client/src/Pages/Settings/SettingsPagespeed.jsx +++ b/client/src/Pages/Settings/SettingsPagespeed.jsx @@ -10,15 +10,17 @@ import { useTheme } from "@emotion/react"; import { PropTypes } from "prop-types"; import { useState } from "react"; import { useTranslation } from "react-i18next"; +import { Controller } from "react-hook-form"; const SettingsPagespeed = ({ isAdmin, HEADING_SX, - settingsData, - setSettingsData, isApiKeySet, apiKeyHasBeenReset, setApiKeyHasBeenReset, + defaults, + control, + setValue, }) => { const { t } = useTranslation(); const theme = useTheme(); @@ -26,15 +28,6 @@ const SettingsPagespeed = ({ // Local state const [apiKey, setApiKey] = useState(""); - // Handler - const handleChange = (e) => { - setApiKey(e.target.value); - setSettingsData({ - ...settingsData, - settings: { ...settingsData.settings, pagespeedApiKey: e.target.value }, - }); - }; - if (!isAdmin) { return null; } @@ -46,35 +39,40 @@ const SettingsPagespeed = ({ component="h1" variant="h2" > - {t("settingsPage.pageSpeedSettings.title")} + {t("pages.settings.pageSpeedSettings.title")} - {t("settingsPage.pageSpeedSettings.description")} + {t("pages.settings.pageSpeedSettings.description")} {(isApiKeySet === false || apiKeyHasBeenReset === true) && ( - } + control={control} + defaultValue={defaults.pagespeedApiKey} + render={({ field, fieldState }) => ( + } + error={!!fieldState.error} + helperText={fieldState.error?.message} + /> + )} /> )} {isApiKeySet === true && apiKeyHasBeenReset === false && ( - {t("settingsPage.pageSpeedSettings.labelApiKeySet")} + + {t("pages.settings.pageSpeedSettings.labelApiKeySet")} + setIsOpen(false)} confirmationButtonLabel={t( - "settingsPage.statsSettings.clearAllStatsDialogConfirm" + "pages.settings.statsSettings.clearAllStatsDialogConfirm" )} - onConfirm={() => { - const syntheticEvent = { - target: { - name: "deleteStats", - }, - }; - handleChange(syntheticEvent); + onConfirm={async () => { + await deleteMonitorStatsFn("/checks/team"); + setIsOpen(false); }} isLoading={false} @@ -77,8 +75,6 @@ const SettingsStats = ({ isAdmin, HEADING_SX, handleChange, settingsData, errors SettingsStats.propTypes = { isAdmin: PropTypes.bool, HEADING_SX: PropTypes.object, - handleChange: PropTypes.func, - settingsData: PropTypes.object, errors: PropTypes.object, }; diff --git a/client/src/Pages/Settings/SettingsTimeZone.jsx b/client/src/Pages/Settings/SettingsTimeZone.jsx index 8ed7e5b3b..444088c8a 100644 --- a/client/src/Pages/Settings/SettingsTimeZone.jsx +++ b/client/src/Pages/Settings/SettingsTimeZone.jsx @@ -7,31 +7,28 @@ import timezones from "@/Utils/timezones.json"; // Utils import { useTheme } from "@emotion/react"; +import { useSelector, useDispatch } from "react-redux"; +import { setTimezone } from "@/Features/UI/uiSlice.js"; import { PropTypes } from "prop-types"; import { useTranslation } from "react-i18next"; import { useCallback, useMemo, useState } from "react"; -const SettingsTimeZone = ({ HEADING_SX, handleChange, timezone }) => { +const SettingsTimeZone = ({ HEADING_SX }) => { const theme = useTheme(); const { t } = useTranslation(); const [rawInput, setRawInput] = useState(""); + const dispatch = useDispatch(); + const { timezone } = useSelector((state) => state.ui); const selectedTimezone = useMemo( () => timezones.find((tz) => tz._id === timezone) ?? null, [timezone] ); - const handleTimezoneChange = useCallback( - (newValue) => { - setRawInput(""); - handleChange({ - target: { - name: "timezone", - value: newValue?._id ?? "", - }, - }); - }, - [handleChange] - ); + const handleTimezoneChange = (newValue) => { + setRawInput(""); + const newId = newValue?._id ?? ""; + dispatch(setTimezone({ timezone: newId })); + }; return ( @@ -40,11 +37,11 @@ const SettingsTimeZone = ({ HEADING_SX, handleChange, timezone }) => { component="h1" variant="h2" > - {t("settingsPage.timezoneSettings.title")} + {t("pages.settings.timezoneSettings.title")} - {t("settingsPage.timezoneSettings.description")} + {t("pages.settings.timezoneSettings.description")} @@ -68,8 +65,6 @@ const SettingsTimeZone = ({ HEADING_SX, handleChange, timezone }) => { SettingsTimeZone.propTypes = { HEADING_SX: PropTypes.object, - handleChange: PropTypes.func, - timezone: PropTypes.string, }; export default SettingsTimeZone; diff --git a/client/src/Pages/Settings/SettingsUI.jsx b/client/src/Pages/Settings/SettingsUI.jsx index ef9f44eaa..aa58a67d9 100644 --- a/client/src/Pages/Settings/SettingsUI.jsx +++ b/client/src/Pages/Settings/SettingsUI.jsx @@ -11,11 +11,19 @@ import { lightTheme, darkTheme } from "@/Utils/Theme/v2Theme"; import { useTheme } from "@emotion/react"; import { PropTypes } from "prop-types"; import { useTranslation } from "react-i18next"; +import { useSelector, useDispatch } from "react-redux"; +import { setMode, setLanguage, setChartType } from "@/Features/UI/uiSlice.js"; -const SettingsUI = ({ HEADING_SX, handleChange, mode, language, chartType }) => { +const SettingsUI = ({ HEADING_SX }) => { + const { + mode, + language = "en", + chartType = "histogram", + } = useSelector((state) => state.ui); const { t, i18n } = useTranslation(); const theme = useTheme(); const languages = Object.keys(i18n.options.resources || {}); + const dispatch = useDispatch(); const v2Theme = mode === "dark" ? darkTheme : lightTheme; return ( @@ -24,18 +32,18 @@ const SettingsUI = ({ HEADING_SX, handleChange, mode, language, chartType }) => component="h1" variant="h2" > - {t("settingsPage.uiSettings.title")} + {t("pages.settings.uiSettings.title")} - {t("settingsPage.uiSettings.description")} + {t("pages.settings.uiSettings.description")} @@ -68,10 +76,6 @@ const SettingsUI = ({ HEADING_SX, handleChange, mode, language, chartType }) => SettingsUI.propTypes = { HEADING_SX: PropTypes.object, - handleChange: PropTypes.func, - mode: PropTypes.string, - language: PropTypes.string, - chartType: PropTypes.string, }; export default SettingsUI; diff --git a/client/src/Pages/Settings/SettingsURL.jsx b/client/src/Pages/Settings/SettingsURL.jsx index c52dcf317..11e7ea821 100644 --- a/client/src/Pages/Settings/SettingsURL.jsx +++ b/client/src/Pages/Settings/SettingsURL.jsx @@ -3,13 +3,14 @@ import Stack from "@mui/material/Stack"; import Typography from "@mui/material/Typography"; import ConfigBox from "@/Components/v1/ConfigBox/index.jsx"; import Select from "@/Components/v1/Inputs/Select/index.jsx"; +import { Controller } from "react-hook-form"; // Utils import { useTheme } from "@emotion/react"; import { PropTypes } from "prop-types"; import { useTranslation } from "react-i18next"; -const SettingsURL = ({ HEADING_SX, handleChange, showURL = false }) => { +const SettingsURL = ({ HEADING_SX, control, defaults }) => { const { t } = useTranslation(); const theme = useTheme(); return ( @@ -19,23 +20,30 @@ const SettingsURL = ({ HEADING_SX, handleChange, showURL = false }) => { component="h1" variant="h2" > - {t("settingsPage.urlSettings.title")} + {t("pages.settings.urlSettings.title")} - {t("settingsPage.urlSettings.description")} + {t("pages.settings.urlSettings.description")} - + control={control} + defaultValue={defaults.showURL} + render={({ field, fieldState }) => ( +