diff --git a/frontend/src/app-components/auth/Login.tsx b/frontend/src/app-components/auth/Login.tsx index 4bc53960..fe9d841b 100755 --- a/frontend/src/app-components/auth/Login.tsx +++ b/frontend/src/app-components/auth/Login.tsx @@ -13,13 +13,12 @@ import { Button, Grid, Paper, Typography } from "@mui/material"; import Link from "next/link"; import { useRouter } from "next/router"; import { useEffect } from "react"; -import { useForm } from "react-hook-form"; import { useConfirmAccount, useLogin } from "@/hooks/entities/auth-hooks"; import { useAuth } from "@/hooks/useAuth"; +import { useForm } from "@/hooks/useForm"; import { useToast } from "@/hooks/useToast"; import { useTranslate } from "@/hooks/useTranslate"; -import { useValidationRules } from "@/hooks/useValidationRules"; import { ILoginAttributes } from "@/types/auth/login.types"; import { PublicContentWrapper } from "../../components/anonymous/PublicContentWrapper"; @@ -64,18 +63,15 @@ export const Login = () => { handleSubmit, } = useForm({ defaultValues: DEFAULT_VALUES, + rules: { + identifier: { + required: t("message.email_is_required"), + }, + password: { + required: t("message.password_is_required"), + }, + }, }); - const rules = useValidationRules(); - const validationRules = { - email: { - ...rules.email, - required: t("message.email_is_required"), - }, - password: { - ...rules.password, - required: t("message.password_is_required"), - }, - }; const onSubmitForm = (data: ILoginAttributes) => { login(data); }; @@ -106,7 +102,7 @@ export const Login = () => { startAdornment: , }} helperText={errors.identifier ? errors.identifier.message : null} - {...register("identifier", validationRules.email)} + {...register("identifier")} /> { startAdornment: , }} helperText={errors.password ? errors.password.message : null} - {...register("password", validationRules.password)} + {...register("password")} /> diff --git a/frontend/src/app-components/auth/Register.tsx b/frontend/src/app-components/auth/Register.tsx index e4e9e91d..a705292e 100644 --- a/frontend/src/app-components/auth/Register.tsx +++ b/frontend/src/app-components/auth/Register.tsx @@ -21,12 +21,11 @@ import { } from "@mui/material"; import { useRouter } from "next/router"; import { useEffect, useState } from "react"; -import { useForm } from "react-hook-form"; import { useAcceptInvite } from "@/hooks/entities/auth-hooks"; +import { useForm } from "@/hooks/useForm"; import { useToast } from "@/hooks/useToast"; import { useTranslate } from "@/hooks/useTranslate"; -import { useValidationRules } from "@/hooks/useValidationRules"; import { IRegisterAttributes } from "@/types/auth/register.types"; import { JWT } from "@/utils/Jwt"; @@ -71,43 +70,38 @@ export const Register = () => { handleSubmit, } = useForm({ defaultValues: DEFAULT_VALUES, + rules: { + first_name: { + required: t("message.first_name_is_required"), + }, + last_name: { + required: t("message.last_name_is_required"), + }, + username: { + required: t("message.username_is_required"), + }, + email: { + required: t("message.email_is_required"), + }, + password: { + required: t("message.password_is_required"), + }, + password2: { + validate: (val) => { + if (val !== watch("password")) { + trigger("password"); + + return t("message.password_match"); + } + }, + }, + }, }); const [isTermsAccepted, setIsTermsAccepted] = useState(false); const [readonlyEmail, setReadonlyEmail] = useState(false); const handleChange = (event: React.ChangeEvent) => { setIsTermsAccepted(event.target.checked); }; - const rules = useValidationRules(); - const validationRules = { - first_name: { - required: t("message.first_name_is_required"), - }, - last_name: { - required: t("message.last_name_is_required"), - }, - username: { - required: t("message.username_is_required"), - }, - email: { - ...rules.email, - required: t("message.email_is_required"), - }, - roles: {}, - token: {}, - password: { - ...rules.password, - required: t("message.password_is_required"), - }, - password2: { - validate: (val?: string) => { - if (val !== watch("password")) { - trigger("password"); - - return t("message.password_match"); - } - }, - }, - }; const onSubmitForm = ({ password2: _password2, ...rest @@ -126,8 +120,6 @@ export const Register = () => { toast.error("Invalid Token"); } else { setValue("token", String(queryToken)); - - // (decodedToken); setValue("email", decodedToken.email); if (decodedToken.roles.length) setValue("roles", decodedToken.roles); @@ -157,7 +149,7 @@ export const Register = () => { error={!!errors.first_name} required autoFocus - {...register("first_name", validationRules.first_name)} + {...register("first_name")} InputProps={{ startAdornment: , }} @@ -171,7 +163,7 @@ export const Register = () => { label={t("placeholder.last_name")} error={!!errors.last_name} required - {...register("last_name", validationRules.last_name)} + {...register("last_name")} InputProps={{ startAdornment: , }} @@ -183,7 +175,7 @@ export const Register = () => { label={t("placeholder.username")} error={!!errors.username} required - {...register("username", validationRules.username)} + {...register("username")} InputProps={{ startAdornment: , }} @@ -195,7 +187,7 @@ export const Register = () => { label={t("placeholder.email")} error={!!errors.email} required - {...register("email", validationRules.email)} + {...register("email")} helperText={errors.email ? errors.email.message : null} InputProps={{ disabled: readonlyEmail, @@ -209,7 +201,7 @@ export const Register = () => { label={t("label.auth_pass")} error={!!errors.password} required - {...register("password", validationRules.password)} + {...register("password")} helperText={errors.password ? errors.password.message : null} InputProps={{ startAdornment: , @@ -221,7 +213,7 @@ export const Register = () => { label={t("placeholder.password2")} error={!!errors.password2} required - {...register("password2", validationRules.password2)} + {...register("password2")} helperText={errors.password2 ? errors.password2.message : null} InputProps={{ startAdornment: , diff --git a/frontend/src/app-components/auth/ResetPassword.tsx b/frontend/src/app-components/auth/ResetPassword.tsx index 9c9c8c8b..77eec42e 100644 --- a/frontend/src/app-components/auth/ResetPassword.tsx +++ b/frontend/src/app-components/auth/ResetPassword.tsx @@ -1,5 +1,5 @@ /* - * Copyright © 2024 Hexastack. All rights reserved. + * Copyright © 2025 Hexastack. All rights reserved. * * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. @@ -10,12 +10,11 @@ import KeyIcon from "@mui/icons-material/Key"; import { Button, Grid, Paper, Typography } from "@mui/material"; import Link from "next/link"; import { useRouter } from "next/router"; -import { useForm } from "react-hook-form"; import { useResetPassword } from "@/hooks/entities/reset-hooks"; +import { useForm } from "@/hooks/useForm"; import { useToast } from "@/hooks/useToast"; import { useTranslate } from "@/hooks/useTranslate"; -import { useValidationRules } from "@/hooks/useValidationRules"; import { PublicContentWrapper } from "../../components/anonymous/PublicContentWrapper"; import { ContentContainer } from "../dialogs"; @@ -25,23 +24,20 @@ import { PasswordInput } from "../inputs/PasswordInput"; export const ResetPassword = () => { const { t } = useTranslate(); const { toast } = useToast(); - const rules = useValidationRules(); - const validationRules = { - password: { - ...rules.password, - required: t("message.password_is_required"), - }, - password2: { - ...rules.password2, - required: t("message.password_is_required"), - }, - }; const { register, handleSubmit, formState: { errors }, } = useForm<{ password: string; password2: string }>({ defaultValues: { password: "", password2: "" }, + rules: { + password: { + required: t("message.password_is_required"), + }, + password2: { + required: t("message.password_is_required"), + }, + }, }); const { query, replace } = useRouter(); // the following typecasting is due to the fact that the query object is not typed @@ -76,7 +72,7 @@ export const ResetPassword = () => { startAdornment: , }} helperText={errors.password ? errors.password.message : null} - {...register("password", validationRules.password)} + {...register("password")} /> { startAdornment: , }} helperText={errors.password2 ? errors.password2.message : null} - {...register("password2", validationRules.password2)} + {...register("password2")} /> diff --git a/frontend/src/app-components/auth/resetPasswordRequest.tsx b/frontend/src/app-components/auth/resetPasswordRequest.tsx index d773ff31..89b27b6e 100644 --- a/frontend/src/app-components/auth/resetPasswordRequest.tsx +++ b/frontend/src/app-components/auth/resetPasswordRequest.tsx @@ -1,5 +1,5 @@ /* - * Copyright © 2024 Hexastack. All rights reserved. + * Copyright © 2025 Hexastack. All rights reserved. * * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. @@ -8,9 +8,9 @@ import { Button, Grid, Paper, Typography } from "@mui/material"; import Link from "next/link"; -import { useForm } from "react-hook-form"; import { useRequestResetPassword } from "@/hooks/entities/reset-hooks"; +import { useForm } from "@/hooks/useForm"; import { useToast } from "@/hooks/useToast"; import { useTranslate } from "@/hooks/useTranslate"; @@ -27,6 +27,11 @@ export const ResetPasswordRequest = () => { formState: { errors }, } = useForm<{ email: string }>({ defaultValues: { email: "" }, + rules: { + email: { + required: t("message.email_is_required"), + }, + }, }); const { mutate: requestReset } = useRequestResetPassword({ onSuccess: () => { @@ -55,9 +60,7 @@ export const ResetPasswordRequest = () => { error={!!errors.email} required autoFocus - {...register("email", { - required: t("message.email_is_required"), - })} + {...register("email")} helperText={errors.email ? errors.email.message : null} /> diff --git a/frontend/src/components/Menu/MenuForm.tsx b/frontend/src/components/Menu/MenuForm.tsx index 9b7105c5..9ba0a993 100644 --- a/frontend/src/components/Menu/MenuForm.tsx +++ b/frontend/src/components/Menu/MenuForm.tsx @@ -8,13 +8,14 @@ import { MenuItem } from "@mui/material"; import { FC, Fragment, useEffect } from "react"; -import { Controller, useForm } from "react-hook-form"; +import { Controller } from "react-hook-form"; import { ContentContainer, ContentItem } from "@/app-components/dialogs"; import { Input } from "@/app-components/inputs/Input"; import { ToggleableInput } from "@/app-components/inputs/ToggleableInput"; import { useCreate } from "@/hooks/crud/useCreate"; import { useUpdate } from "@/hooks/crud/useUpdate"; +import { useForm } from "@/hooks/useForm"; import { useToast } from "@/hooks/useToast"; import { useTranslate } from "@/hooks/useTranslate"; import { EntityType } from "@/services/types"; @@ -60,19 +61,18 @@ export const MenuForm: FC> = ({ handleSubmit, } = useForm({ defaultValues: DEFAULT_VALUES, + rules: { + type: { + required: t("message.type_is_required"), + }, + title: { required: t("message.title_is_required") }, + url: { + required: t("message.url_is_invalid"), + validate: (value: string = "") => + isAbsoluteUrl(value) || t("message.url_is_invalid"), + }, + }, }); - const validationRules = { - type: { - required: t("message.type_is_required"), - }, - title: { required: t("message.title_is_required") }, - url: { - required: t("message.url_is_invalid"), - validate: (value: string = "") => - isAbsoluteUrl(value) || t("message.url_is_invalid"), - }, - payload: {}, - }; const typeValue = watch("type"); const titleValue = watch("title"); const onSubmitForm = (params: IMenuItemAttributes) => { @@ -102,46 +102,35 @@ export const MenuForm: FC> = ({
- - { - const { onChange, ...rest } = field; - - return ( - { - onChange(value); - resetField("url"); - }} - helperText={errors.type ? errors.type.message : null} - {...rest} - > - {Object.keys(MenuType).map((value, key) => ( - - {t(`label.${value}`)} - - ))} - - ); - }} - /> - + { + resetField("url"); + }, + })} + helperText={errors.type ? errors.type.message : null} + {...rest} + > + {Object.keys(MenuType).map((value, key) => ( + + {t(`label.${value}`)} + + ))} + + + @@ -152,7 +141,7 @@ export const MenuForm: FC> = ({ error={!!errors.url} required helperText={errors.url ? errors.url.message : null} - {...register("url", validationRules.url)} + {...register("url")} /> ) : typeValue === MenuType.postback ? ( > = ({ formState: { errors }, handleSubmit, } = useForm({ - defaultValues: { label: category?.label || "" }, - }); - const validationRules = { - label: { - required: t("message.label_is_required"), + rules: { + label: { required: t("message.label_is_required") }, }, - }; + }); const onSubmitForm = (params: ICategoryAttributes) => { if (category) { updateCategory({ id: category.id, params }); @@ -81,7 +78,7 @@ export const CategoryForm: FC> = ({ > = ({ name: contentType?.name || "", fields: contentType?.fields || FIELDS_FORM_DEFAULT_VALUES, }, + rules: { + name: { + required: t("message.name_is_required"), + }, + }, }); const { append, fields, remove } = useFieldArray({ name: "fields", @@ -113,9 +119,7 @@ export const ContentTypeForm: FC> = ({ > = ({ label: contextVar?.label || "", permanent: contextVar?.permanent || false, }, - }); - const validationRules = { - name: { - pattern: { - value: /^[a-z_0-9]+$/, - message: t("message.context_vars_name_is_invalid"), + rules: { + name: { + pattern: { + value: /^[a-z_0-9]+$/, + message: t("message.context_vars_name_is_invalid"), + }, + }, + label: { + required: t("message.label_is_required"), }, }, - label: { - required: t("message.label_is_required"), - }, - }; + }); const onSubmitForm = (params: IContextVarAttributes) => { if (contextVar) { updateContextVar({ id: contextVar.id, params }); @@ -102,7 +103,7 @@ export const ContextVarForm: FC> = ({ error={!!errors.label} required autoFocus - {...register("label", validationRules.label)} + {...register("label")} InputProps={{ onChange: ({ target: { value } }) => { setValue("label", value); @@ -117,7 +118,7 @@ export const ContextVarForm: FC> = ({ label={t("label.name")} error={!!errors.name} disabled - {...register("name", validationRules.name)} + {...register("name")} helperText={errors.name ? errors.name.message : null} InputLabelProps={{ shrink: true }} /> diff --git a/frontend/src/components/labels/LabelForm.tsx b/frontend/src/components/labels/LabelForm.tsx index ebc9654a..d2bb7d84 100644 --- a/frontend/src/components/labels/LabelForm.tsx +++ b/frontend/src/components/labels/LabelForm.tsx @@ -7,12 +7,12 @@ */ import { FC, Fragment, useEffect } from "react"; -import { useForm } from "react-hook-form"; import { ContentContainer, ContentItem } from "@/app-components/dialogs"; import { Input } from "@/app-components/inputs/Input"; import { useCreate } from "@/hooks/crud/useCreate"; import { useUpdate } from "@/hooks/crud/useUpdate"; +import { useForm } from "@/hooks/useForm"; import { useToast } from "@/hooks/useToast"; import { useTranslate } from "@/hooks/useTranslate"; import { EntityType } from "@/services/types"; @@ -52,14 +52,12 @@ export const LabelForm: FC> = ({ title: label?.title || "", description: label?.description || "", }, - }); - const validationRules = { - title: { - required: t("message.title_is_required"), + rules: { + title: { + required: t("message.title_is_required"), + }, }, - name: {}, - description: {}, - }; + }); const onSubmitForm = (params: ILabelAttributes) => { if (label) { updateLabel({ id: label.id, params }); @@ -90,7 +88,7 @@ export const LabelForm: FC> = ({ error={!!errors.title} required autoFocus - {...register("title", validationRules.title)} + {...register("title")} InputProps={{ onChange: ({ target: { value } }) => { setValue("title", value); @@ -104,7 +102,7 @@ export const LabelForm: FC> = ({ @@ -113,7 +111,7 @@ export const LabelForm: FC> = ({ > = ({ code: language?.code || "", isRTL: language?.isRTL || false, }, + rules: { + title: { + required: t("message.title_is_required"), + }, + code: { + required: t("message.code_is_required"), + }, + }, }); - const validationRules = { - title: { - required: t("message.title_is_required"), - }, - code: { - required: t("message.code_is_required"), - }, - }; const onSubmitForm = (params: ILanguageAttributes) => { if (language) { updateLanguage({ id: language.id, params }); @@ -87,9 +88,10 @@ export const LanguageForm: FC> = ({ > = ({ diff --git a/frontend/src/components/nlp/components/NlpEntityForm.tsx b/frontend/src/components/nlp/components/NlpEntityForm.tsx index 3c21b5af..e068a287 100644 --- a/frontend/src/components/nlp/components/NlpEntityForm.tsx +++ b/frontend/src/components/nlp/components/NlpEntityForm.tsx @@ -14,12 +14,12 @@ import { RadioGroup, } from "@mui/material"; import { FC, Fragment, useEffect } from "react"; -import { useForm } from "react-hook-form"; import { ContentContainer, ContentItem } from "@/app-components/dialogs"; import { Input } from "@/app-components/inputs/Input"; import { useCreate } from "@/hooks/crud/useCreate"; import { useUpdate } from "@/hooks/crud/useUpdate"; +import { useForm } from "@/hooks/useForm"; import { useToast } from "@/hooks/useToast"; import { useTranslate } from "@/hooks/useTranslate"; import { EntityType } from "@/services/types"; @@ -62,14 +62,12 @@ export const NlpEntityVarForm: FC> = ({ lookups: nlpEntity?.lookups || ["keywords"], weight: nlpEntity?.weight || 1, }, - }); - const validationRules = { - name: { - required: t("message.name_is_required"), + rules: { + name: { + required: t("message.name_is_required"), + }, }, - lookups: {}, - isChecked: {}, - }; + }); const onSubmitForm = (params: INlpEntityAttributes) => { if (nlpEntity) { updateNlpEntity({ id: nlpEntity.id, params }); @@ -122,7 +120,7 @@ export const NlpEntityVarForm: FC> = ({ = ({ ))} - { - /* Keyword entities */ - } + {/* Keyword entities */} {keywordEntities.map((keywordEntity, index) => ( = ({ user }) => { email: user.email, language: user.language, }, - }); - const rules = useValidationRules(); - const validationRules = { - ...rules, - email: { - ...rules.email, - required: t("message.email_is_required"), - }, - password: { - ...rules.password, - }, - password2: { - validate: (val?: string) => { - if (val !== watch("password")) { - trigger("password"); + rules: { + password2: { + validate: (val) => { + if (val !== watch("password")) { + trigger("password"); - return t("message.password_match"); - } + return t("message.password_match"); + } + }, }, }, - }; + }); const onSubmitForm = ({ password, password2: _password2, @@ -124,7 +115,7 @@ export const ProfileForm: FC = ({ user }) => { = ({ user }) => { @@ -166,7 +157,7 @@ export const ProfileForm: FC = ({ user }) => { = ({ user }) => { = ({ user }) => { > = ({ formState: { errors }, } = useForm({ defaultValues: { name: "" }, - }); - const validationRules = { - name: { - required: t("message.name_is_required"), + rules: { + name: { + required: t("message.name_is_required"), + }, }, - }; + }); const onSubmitForm = (params: IRoleAttributes) => { if (role) { updateRole({ id: role.id, params }); @@ -80,7 +80,7 @@ export const RoleForm: FC> = ({ required autoFocus helperText={errors.name ? errors.name.message : null} - {...register("name", validationRules.name)} + {...register("name")} /> diff --git a/frontend/src/components/translations/TranslationForm.tsx b/frontend/src/components/translations/TranslationForm.tsx index b9d7f34d..72db7a61 100644 --- a/frontend/src/components/translations/TranslationForm.tsx +++ b/frontend/src/components/translations/TranslationForm.tsx @@ -8,12 +8,13 @@ import { FormLabel, Grid, Typography } from "@mui/material"; import { FC, Fragment } from "react"; -import { Controller, ControllerRenderProps, useForm } from "react-hook-form"; +import { Controller, ControllerRenderProps } from "react-hook-form"; import { ContentContainer, ContentItem } from "@/app-components/dialogs"; import { Input } from "@/app-components/inputs/Input"; import { useFind } from "@/hooks/crud/useFind"; import { useUpdate } from "@/hooks/crud/useUpdate"; +import { useForm } from "@/hooks/useForm"; import { useToast } from "@/hooks/useToast"; import { useTranslate } from "@/hooks/useTranslate"; import { EntityType } from "@/services/types"; diff --git a/frontend/src/components/users/InviteUserForm.tsx b/frontend/src/components/users/InviteUserForm.tsx index 34c1efb1..64919691 100644 --- a/frontend/src/components/users/InviteUserForm.tsx +++ b/frontend/src/components/users/InviteUserForm.tsx @@ -7,15 +7,15 @@ */ import { FC, Fragment } from "react"; -import { Controller, useForm } from "react-hook-form"; +import { Controller } from "react-hook-form"; import { ContentContainer, ContentItem } from "@/app-components/dialogs"; import AutoCompleteEntitySelect from "@/app-components/inputs/AutoCompleteEntitySelect"; import { Input } from "@/app-components/inputs/Input"; import { useSendInvitation } from "@/hooks/entities/invitation-hooks"; +import { useForm } from "@/hooks/useForm"; import { useToast } from "@/hooks/useToast"; import { useTranslate } from "@/hooks/useTranslate"; -import { useValidationRules } from "@/hooks/useValidationRules"; import { EntityType, Format } from "@/services/types"; import { ComponentFormProps } from "@/types/common/dialogs.types"; import { IInvitationAttributes } from "@/types/invitation.types"; @@ -47,17 +47,12 @@ export const InviteUserForm: FC> = ({ handleSubmit, } = useForm({ defaultValues: DEFAULT_VALUES, + rules: { + email: { + required: t("message.email_is_required"), + }, + }, }); - const rules = useValidationRules(); - const validationRules = { - email: { - ...rules.email, - required: t("message.email_is_required"), - }, - roles: { - required: t("message.roles_is_required"), - }, - }; const onSubmitForm = (params: IInvitationAttributes) => sendInvitation(params); @@ -71,14 +66,16 @@ export const InviteUserForm: FC> = ({ error={!!errors.email} required autoFocus - {...register("email", validationRules.email)} + {...register("email")} helperText={errors.email ? errors.email.message : null} /> { const { onChange, ...rest } = field; diff --git a/frontend/src/components/visual-editor/BlockEditForm.tsx b/frontend/src/components/visual-editor/BlockEditForm.tsx index 59cb0d82..23435648 100644 --- a/frontend/src/components/visual-editor/BlockEditForm.tsx +++ b/frontend/src/components/visual-editor/BlockEditForm.tsx @@ -10,13 +10,14 @@ import ChatBubbleOutlineOutlinedIcon from "@mui/icons-material/ChatBubbleOutline import SettingsApplicationsIcon from "@mui/icons-material/SettingsApplications"; import { FormControlLabel, Grid, Switch, Tab, Tabs } from "@mui/material"; import { FC, Fragment, useEffect, useState } from "react"; -import { Controller, useForm } from "react-hook-form"; +import { Controller } from "react-hook-form"; import { ContentContainer, ContentItem } from "@/app-components/dialogs"; import { Input } from "@/app-components/inputs/Input"; import TriggerIcon from "@/app-components/svg/TriggerIcon"; import { TabPanel } from "@/app-components/tabs/TabPanel"; import { useUpdate } from "@/hooks/crud/useUpdate"; +import { useForm } from "@/hooks/useForm"; import { useToast } from "@/hooks/useToast"; import { useTranslate } from "@/hooks/useTranslate"; import { EntityType } from "@/services/types"; @@ -82,6 +83,11 @@ export const BlockEditForm: FC> = ({ } as IBlockAttributes; const methods = useForm({ defaultValues: DEFAULT_VALUES, + rules: { + name: { + required: t("message.name_is_required"), + }, + }, }); const { reset, @@ -90,11 +96,6 @@ export const BlockEditForm: FC> = ({ handleSubmit, control, } = methods; - const validationRules = { - name: { - required: t("message.name_is_required"), - }, - }; const onSubmitForm = (params: IBlockAttributes) => { if (block) { updateBlock({ id: block.id, params }); @@ -121,8 +122,9 @@ export const BlockEditForm: FC> = ({