mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
fix: form validations (#213)
This commit is contained in:
parent
27e3364a1f
commit
60a35e6af1
@ -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..."
|
||||||
|
@ -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",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
);
|
);
|
||||||
|
@ -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>
|
||||||
|
@ -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}
|
||||||
|
Loading…
Reference in New Issue
Block a user