fix: form validations (#213)

This commit is contained in:
Aaryan Khandelwal 2023-01-31 18:10:50 +05:30 committed by GitHub
parent 27e3364a1f
commit 60a35e6af1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 68 additions and 21 deletions

View File

@ -18,6 +18,7 @@ const RemirrorRichTextEditor = dynamic(() => import("components/rich-text-editor
}); });
// types // types
import { IIssue } from "types"; import { IIssue } from "types";
import useToast from "hooks/use-toast";
export interface IssueDescriptionFormValues { export interface IssueDescriptionFormValues {
name: string; name: string;
@ -31,7 +32,16 @@ export interface IssueDetailsProps {
} }
export const IssueDescriptionForm: FC<IssueDetailsProps> = ({ issue, handleFormSubmit }) => { export const IssueDescriptionForm: FC<IssueDetailsProps> = ({ issue, handleFormSubmit }) => {
const { handleSubmit, watch, setValue, reset } = useForm<IIssue>({ const { setToastAlert } = useToast();
const {
handleSubmit,
watch,
setValue,
reset,
formState: { errors },
setError,
} = useForm<IIssue>({
defaultValues: { defaultValues: {
name: "", name: "",
description: "", description: "",
@ -41,13 +51,31 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({ issue, handleFormS
const handleDescriptionFormSubmit = useCallback( const handleDescriptionFormSubmit = useCallback(
(formData: Partial<IIssue>) => { (formData: Partial<IIssue>) => {
if (!formData.name || formData.name === "") {
setToastAlert({
type: "error",
title: "Error in saving!",
message: "Title is required.",
});
return;
}
if (formData.name.length > 255) {
setToastAlert({
type: "error",
title: "Error in saving!",
message: "Title cannot have more than 255 characters.",
});
return;
}
handleFormSubmit({ handleFormSubmit({
name: formData.name ?? "", name: formData.name ?? "",
description: formData.description, description: formData.description,
description_html: formData.description_html, description_html: formData.description_html,
}); });
}, },
[handleFormSubmit] [handleFormSubmit, setToastAlert]
); );
const debounceHandler = useMemo( const debounceHandler = useMemo(
@ -83,9 +111,8 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({ issue, handleFormS
}} }}
mode="transparent" mode="transparent"
className="text-xl font-medium" className="text-xl font-medium"
required={true}
/> />
<span>{errors.name ? errors.name.message : null}</span>
<RemirrorRichTextEditor <RemirrorRichTextEditor
value={watch("description")} value={watch("description")}
placeholder="Describe the issue..." placeholder="Describe the issue..."

View File

@ -197,7 +197,7 @@ export const IssueForm: FC<IssueFormProps> = ({
required: "Title is required", required: "Title is required",
maxLength: { maxLength: {
value: 255, value: 255,
message: "Name should be less than 255 characters", message: "Title should be less than 255 characters",
}, },
}} }}
/> />

View File

@ -93,9 +93,8 @@ export const CreateProjectModal: React.FC<Props> = (props) => {
const projectIdentifier = watch("identifier") ?? ""; const projectIdentifier = watch("identifier") ?? "";
useEffect(() => { useEffect(() => {
if (projectName && isChangeIdentifierRequired) { if (projectName && isChangeIdentifierRequired)
setValue("identifier", projectName.replace(/ /g, "").toUpperCase().substring(0, 3)); setValue("identifier", projectName.replace(/ /g, "").toUpperCase().substring(0, 3));
}
}, [projectName, projectIdentifier, setValue, isChangeIdentifierRequired]); }, [projectName, projectIdentifier, setValue, isChangeIdentifierRequired]);
useEffect(() => () => setIsChangeIdentifierRequired(true), [isOpen]); useEffect(() => () => setIsChangeIdentifierRequired(true), [isOpen]);
@ -215,6 +214,10 @@ export const CreateProjectModal: React.FC<Props> = (props) => {
register={register} register={register}
validations={{ validations={{
required: "Name is required", required: "Name is required",
maxLength: {
value: 255,
message: "Name should be less than 255 characters",
},
}} }}
/> />
</div> </div>

View File

@ -162,6 +162,10 @@ const CreateUpdateCycleModal: React.FC<Props> = ({ isOpen, setIsOpen, data, proj
register={register} register={register}
validations={{ validations={{
required: "Name is required", required: "Name is required",
maxLength: {
value: 255,
message: "Name should be less than 255 characters",
},
}} }}
/> />
</div> </div>

View File

@ -13,7 +13,7 @@ import stateService from "services/state.service";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
// ui // ui
import { Button, Input, Select } from "components/ui"; import { Button, CustomSelect, Input, Select } from "components/ui";
// types // types
import type { IState } from "types"; import type { IState } from "types";
// fetch-keys // fetch-keys
@ -183,18 +183,27 @@ export const CreateUpdateStateInline: React.FC<Props> = ({
autoComplete="off" autoComplete="off"
/> />
{data && ( {data && (
<Select <Controller
id="group"
name="group" name="group"
error={errors.group} control={control}
register={register} render={({ field: { value, onChange } }) => (
validations={{ <CustomSelect
required: true, value={value}
}} onChange={onChange}
options={Object.keys(GROUP_CHOICES).map((key) => ({ label={
value: key, Object.keys(GROUP_CHOICES).find((k) => k === value.toString())
label: GROUP_CHOICES[key as keyof typeof GROUP_CHOICES], ? GROUP_CHOICES[value.toString() as keyof typeof GROUP_CHOICES]
}))} : "Select group"
}
input
>
{Object.keys(GROUP_CHOICES).map((key) => (
<CustomSelect.Option key={key} value={key}>
{GROUP_CHOICES[key as keyof typeof GROUP_CHOICES]}
</CustomSelect.Option>
))}
</CustomSelect>
)}
/> />
)} )}
<Input <Input
@ -209,7 +218,7 @@ export const CreateUpdateStateInline: React.FC<Props> = ({
Cancel Cancel
</Button> </Button>
<Button theme="primary" disabled={isSubmitting} type="submit"> <Button theme="primary" disabled={isSubmitting} type="submit">
{isSubmitting ? "Loading..." : data ? "Update" : "Create"} {isSubmitting ? (data ? "Updating..." : "Creating...") : data ? "Update" : "Create"}
</Button> </Button>
</form> </form>
); );

View File

@ -178,6 +178,10 @@ const CreateUpdateModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, data, pro
register={register} register={register}
validations={{ validations={{
required: "Name is required", required: "Name is required",
maxLength: {
value: 255,
message: "Name should be less than 255 characters",
},
}} }}
/> />
</div> </div>

View File

@ -32,7 +32,7 @@ export const CustomDatePicker: React.FC<Props> = ({
renderAs === "input" renderAs === "input"
? "block bg-transparent text-sm focus:outline-none rounded-md border border-gray-300 px-3 py-2 w-full cursor-pointer" ? "block bg-transparent text-sm focus:outline-none rounded-md border border-gray-300 px-3 py-2 w-full cursor-pointer"
: renderAs === "button" : renderAs === "button"
? "w-full cursor-pointer rounded-md border px-2 py-1 text-xs shadow-sm duration-300 hover:bg-gray-100 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500" ? "w-full rounded-md border px-2 py-1 text-xs shadow-sm hover:bg-gray-100 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 duration-300 cursor-pointer"
: "" : ""
} ${error ? "border-red-500 bg-red-200" : ""} bg-transparent caret-transparent`} } ${error ? "border-red-500 bg-red-200" : ""} bg-transparent caret-transparent`}
isClearable={isClearable} isClearable={isClearable}