refactor(frontend): use new useForm hook

This commit is contained in:
yassinedorbozgithub
2025-05-26 06:53:23 +01:00
parent 31f22068a8
commit a9be4526a8
18 changed files with 206 additions and 239 deletions

View File

@@ -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<ILoginAttributes>({
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: <Adornment Icon={EmailIcon} />,
}}
helperText={errors.identifier ? errors.identifier.message : null}
{...register("identifier", validationRules.email)}
{...register("identifier")}
/>
<PasswordInput
@@ -117,7 +113,7 @@ export const Login = () => {
startAdornment: <Adornment Icon={KeyIcon} />,
}}
helperText={errors.password ? errors.password.message : null}
{...register("password", validationRules.password)}
{...register("password")}
/>
<Grid container gap={2} justifyContent="space-between">
<Grid alignContent="center">

View File

@@ -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<TRegisterExtendedPayload>({
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<boolean>(false);
const [readonlyEmail, setReadonlyEmail] = useState<boolean>(false);
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
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: <Adornment Icon={AbcIcon} />,
}}
@@ -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: <Adornment Icon={AbcIcon} />,
}}
@@ -183,7 +175,7 @@ export const Register = () => {
label={t("placeholder.username")}
error={!!errors.username}
required
{...register("username", validationRules.username)}
{...register("username")}
InputProps={{
startAdornment: <Adornment Icon={PersonIcon} />,
}}
@@ -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: <Adornment Icon={KeyIcon} />,
@@ -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: <Adornment Icon={KeyIcon} />,

View File

@@ -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: <Adornment Icon={KeyIcon} />,
}}
helperText={errors.password ? errors.password.message : null}
{...register("password", validationRules.password)}
{...register("password")}
/>
<PasswordInput
@@ -87,7 +83,7 @@ export const ResetPassword = () => {
startAdornment: <Adornment Icon={KeyIcon} />,
}}
helperText={errors.password2 ? errors.password2.message : null}
{...register("password2", validationRules.password2)}
{...register("password2")}
/>
<Grid container gap={1} justifyContent="flex-end">
<Button type="submit">{t("button.submit")}</Button>

View File

@@ -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}
/>
<Grid container gap={1} justifyContent="flex-end">

View File

@@ -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<ComponentFormProps<MenuFormData>> = ({
handleSubmit,
} = useForm<IMenuItemAttributes>({
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<ComponentFormProps<MenuFormData>> = ({
<form onSubmit={handleSubmit(onSubmitForm)}>
<ContentContainer>
<ContentContainer flexDirection="row">
<ContentItem>
<Controller
name="type"
rules={validationRules.type}
control={control}
render={({ field }) => {
const { onChange, ...rest } = field;
return (
<Input
select
label={t("placeholder.type")}
error={!!errors.type}
inputRef={field.ref}
required
onChange={({ target: { value } }) => {
onChange(value);
resetField("url");
}}
helperText={errors.type ? errors.type.message : null}
{...rest}
>
{Object.keys(MenuType).map((value, key) => (
<MenuItem value={value} key={key}>
{t(`label.${value}`)}
</MenuItem>
))}
</Input>
);
}}
/>
</ContentItem>
<ContentItem flex={1}>
<Input
select
label={t("placeholder.type")}
error={!!errors.type}
required
{...register("type", {
onChange: () => {
resetField("url");
},
})}
helperText={errors.type ? errors.type.message : null}
{...rest}
>
{Object.keys(MenuType).map((value, key) => (
<MenuItem value={value} key={key}>
{t(`label.${value}`)}
</MenuItem>
))}
</Input>
</ContentItem>
<ContentItem flex={2}>
<Input
label={t("placeholder.title")}
error={!!errors.title}
required
autoFocus
helperText={errors.title ? errors.title.message : null}
{...register("title", validationRules.title)}
{...register("title")}
/>
</ContentItem>
</ContentContainer>
@@ -152,7 +141,7 @@ export const MenuForm: FC<ComponentFormProps<MenuFormData>> = ({
error={!!errors.url}
required
helperText={errors.url ? errors.url.message : null}
{...register("url", validationRules.url)}
{...register("url")}
/>
) : typeValue === MenuType.postback ? (
<Controller

View File

@@ -8,12 +8,12 @@
import { useRouter } from "next/router";
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, RouterType } from "@/services/types";
@@ -48,13 +48,10 @@ export const CategoryForm: FC<ComponentFormProps<ICategory>> = ({
formState: { errors },
handleSubmit,
} = useForm<ICategoryAttributes>({
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<ComponentFormProps<ICategory>> = ({
<Input
label={t("placeholder.label")}
error={!!errors.label}
{...register("label", validationRules.label)}
{...register("label")}
required
autoFocus
helperText={errors.label ? errors.label.message : null}

View File

@@ -9,12 +9,13 @@
import AddIcon from "@mui/icons-material/Add";
import { Button } from "@mui/material";
import { FC, Fragment, useEffect } from "react";
import { useFieldArray, useForm } from "react-hook-form";
import { useFieldArray } 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";
@@ -44,6 +45,11 @@ export const ContentTypeForm: FC<ComponentFormProps<IContentType>> = ({
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<ComponentFormProps<IContentType>> = ({
<Input
label={t("label.name")}
error={!!errors.name}
{...register("name", {
required: t("message.name_is_required"),
})}
{...register("name")}
helperText={errors.name ? errors.name.message : null}
required
autoFocus

View File

@@ -13,7 +13,6 @@ import {
Controller,
ControllerRenderProps,
FieldErrors,
useForm,
} from "react-hook-form";
import AttachmentInput from "@/app-components/attachment/AttachmentInput";
@@ -22,6 +21,7 @@ import { Adornment } from "@/app-components/inputs/Adornment";
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";

View File

@@ -8,12 +8,13 @@
import { FormControlLabel, FormHelperText, Switch } 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 { 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,18 +61,18 @@ export const ContextVarForm: FC<ComponentFormProps<IContextVar>> = ({
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<ComponentFormProps<IContextVar>> = ({
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<ComponentFormProps<IContextVar>> = ({
label={t("label.name")}
error={!!errors.name}
disabled
{...register("name", validationRules.name)}
{...register("name")}
helperText={errors.name ? errors.name.message : null}
InputLabelProps={{ shrink: true }}
/>

View File

@@ -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<ComponentFormProps<ILabel>> = ({
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<ComponentFormProps<ILabel>> = ({
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<ComponentFormProps<ILabel>> = ({
<Input
placeholder={t("placeholder.name")}
error={!!errors.name}
{...register("name", validationRules.name)}
{...register("name")}
disabled
helperText={errors.name ? errors.name.message : null}
/>
@@ -113,7 +111,7 @@ export const LabelForm: FC<ComponentFormProps<ILabel>> = ({
<Input
label={t("label.description")}
error={!!errors.description}
{...register("description", validationRules.description)}
{...register("description")}
helperText={
errors.description ? errors.description.message : null
}

View File

@@ -8,12 +8,13 @@
import { FormControlLabel, Switch } 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 { 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,15 +53,15 @@ export const LanguageForm: FC<ComponentFormProps<ILanguage>> = ({
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<ComponentFormProps<ILanguage>> = ({
<ContentContainer>
<ContentItem>
<Input
required
label={t("label.title")}
error={!!errors.title}
{...register("title", validationRules.title)}
{...register("title")}
multiline={true}
autoFocus
helperText={errors.title ? errors.title.message : null}
@@ -97,9 +99,10 @@ export const LanguageForm: FC<ComponentFormProps<ILanguage>> = ({
</ContentItem>
<ContentItem>
<Input
required
label={t("label.code")}
error={!!errors.code}
{...register("code", validationRules.code)}
{...register("code")}
multiline={true}
helperText={errors.code ? errors.code.message : null}
/>

View File

@@ -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<ComponentFormProps<INlpEntity>> = ({
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<ComponentFormProps<INlpEntity>> = ({
<Input
label={t("label.name")}
error={!!errors.name}
{...register("name", validationRules.name)}
{...register("name")}
required
autoFocus
helperText={errors.name ? errors.name.message : null}

View File

@@ -23,7 +23,7 @@ import {
Typography,
} from "@mui/material";
import { FC, useCallback, useEffect, useMemo, useState } from "react";
import { Controller, useFieldArray, useForm } from "react-hook-form";
import { Controller, useFieldArray } from "react-hook-form";
import { useQuery } from "react-query";
import { ContentContainer, ContentItem } from "@/app-components/dialogs";
@@ -32,6 +32,7 @@ import AutoCompleteSelect from "@/app-components/inputs/AutoCompleteSelect";
import Selectable from "@/app-components/inputs/Selectable";
import { useGetFromCache } from "@/hooks/crud/useGet";
import { useApiClient } from "@/hooks/useApiClient";
import { useForm } from "@/hooks/useForm";
import { useNlp } from "@/hooks/useNlp";
import { useTranslate } from "@/hooks/useTranslate";
import { EntityType, Format } from "@/services/types";
@@ -322,9 +323,7 @@ const NlpDatasetSample: FC<NlpDatasetSampleProps> = ({
</ContentItem>
))}
</Box>
{
/* Keyword entities */
}
{/* Keyword entities */}
<Box display="flex" flexDirection="column">
{keywordEntities.map((keywordEntity, index) => (
<ContentItem

View File

@@ -12,7 +12,7 @@ import KeyIcon from "@mui/icons-material/Key";
import LanguageIcon from "@mui/icons-material/Language";
import { Box, Button, Grid, MenuItem, Typography } from "@mui/material";
import { FC } from "react";
import { Controller, useForm } from "react-hook-form";
import { Controller } from "react-hook-form";
import { useQueryClient } from "react-query";
import { ContentContainer, ContentItem } from "@/app-components/dialogs";
@@ -22,9 +22,9 @@ import { Input } from "@/app-components/inputs/Input";
import { PasswordInput } from "@/app-components/inputs/PasswordInput";
import { useUpdateProfile } from "@/hooks/entities/auth-hooks";
import { CURRENT_USER_KEY } from "@/hooks/useAuth";
import { useForm } from "@/hooks/useForm";
import { useToast } from "@/hooks/useToast";
import { useTranslate } from "@/hooks/useTranslate";
import { useValidationRules } from "@/hooks/useValidationRules";
import { IProfileAttributes, IUser } from "@/types/user.types";
import { MIME_TYPES } from "@/utils/attachment";
@@ -58,27 +58,18 @@ export const ProfileForm: FC<ProfileFormProps> = ({ 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<ProfileFormProps> = ({ user }) => {
<ContentItem>
<Input
label={t("label.user_first_name")}
{...register("first_name", validationRules.first_name)}
{...register("first_name")}
autoFocus
error={!!errors.first_name}
helperText={
@@ -135,7 +126,7 @@ export const ProfileForm: FC<ProfileFormProps> = ({ user }) => {
<ContentItem>
<Input
label={t("label.last_name")}
{...register("last_name", validationRules.last_name)}
{...register("last_name")}
error={!!errors.last_name}
helperText={errors.last_name ? errors.last_name.message : null}
/>
@@ -166,7 +157,7 @@ export const ProfileForm: FC<ProfileFormProps> = ({ user }) => {
<ContentItem>
<Input
label={t("label.email")}
{...register("email", validationRules.email)}
{...register("email")}
required
error={!!errors.email}
helperText={errors.email ? errors.email.message : null}
@@ -178,7 +169,7 @@ export const ProfileForm: FC<ProfileFormProps> = ({ user }) => {
<ContentItem>
<PasswordInput
label={t("placeholder.password")}
{...register("password", validationRules.password)}
{...register("password")}
required
error={!!errors.password}
helperText={errors.password ? errors.password.message : null}
@@ -190,7 +181,7 @@ export const ProfileForm: FC<ProfileFormProps> = ({ user }) => {
<ContentItem>
<PasswordInput
label={t("placeholder.password2")}
{...register("password2", validationRules.password2)}
{...register("password2")}
required
error={!!errors.password2}
helperText={errors.password2 ? errors.password2.message : null}

View File

@@ -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";
@@ -45,12 +45,12 @@ export const RoleForm: FC<ComponentFormProps<IRole>> = ({
formState: { errors },
} = useForm<IRoleAttributes>({
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<ComponentFormProps<IRole>> = ({
required
autoFocus
helperText={errors.name ? errors.name.message : null}
{...register("name", validationRules.name)}
{...register("name")}
/>
</ContentItem>
</ContentContainer>

View File

@@ -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";

View File

@@ -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<ComponentFormProps<undefined>> = ({
handleSubmit,
} = useForm<IInvitationAttributes>({
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<ComponentFormProps<undefined>> = ({
error={!!errors.email}
required
autoFocus
{...register("email", validationRules.email)}
{...register("email")}
helperText={errors.email ? errors.email.message : null}
/>
</ContentItem>
<ContentItem>
<Controller
name="roles"
rules={validationRules.roles}
rules={{
required: t("message.roles_is_required"),
}}
control={control}
render={({ field }) => {
const { onChange, ...rest } = field;

View File

@@ -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<ComponentFormProps<IBlock>> = ({
} as IBlockAttributes;
const methods = useForm<IBlockAttributes>({
defaultValues: DEFAULT_VALUES,
rules: {
name: {
required: t("message.name_is_required"),
},
},
});
const {
reset,
@@ -90,11 +96,6 @@ export const BlockEditForm: FC<ComponentFormProps<IBlock>> = ({
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<ComponentFormProps<IBlock>> = ({
<ContentContainer>
<ContentItem display="flex" gap={5}>
<Input
required
label={t("placeholder.name")}
{...register("name", validationRules.name)}
{...register("name")}
error={!!errors.name}
autoFocus
helperText={errors.name ? errors.name.message : null}