forked from github/plane
feat: cycle modal date validation
This commit is contained in:
parent
17e09d70e2
commit
19e9f510bc
@ -1,11 +1,16 @@
|
|||||||
import { useEffect } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
|
// toast
|
||||||
|
import useToast from "hooks/use-toast";
|
||||||
// react-hook-form
|
// react-hook-form
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
// ui
|
// ui
|
||||||
import { Button, CustomDatePicker, CustomSelect, Input, TextArea } from "components/ui";
|
import { Button, CustomDatePicker, CustomSelect, Input, TextArea } from "components/ui";
|
||||||
// types
|
// types
|
||||||
import { ICycle } from "types";
|
import { ICycle } from "types";
|
||||||
|
// services
|
||||||
|
import cyclesService from "services/cycles.service";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
handleFormSubmit: (values: Partial<ICycle>) => Promise<void>;
|
handleFormSubmit: (values: Partial<ICycle>) => Promise<void>;
|
||||||
@ -23,11 +28,19 @@ const defaultValues: Partial<ICycle> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const CycleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, status, data }) => {
|
export const CycleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, status, data }) => {
|
||||||
|
const router = useRouter();
|
||||||
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
|
const [isDateValid, setIsDateValid] = useState(true);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
formState: { errors, isSubmitting },
|
formState: { errors, isSubmitting },
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
control,
|
control,
|
||||||
|
watch,
|
||||||
reset,
|
reset,
|
||||||
} = useForm<ICycle>({
|
} = useForm<ICycle>({
|
||||||
defaultValues,
|
defaultValues,
|
||||||
@ -41,6 +54,31 @@ export const CycleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, stat
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const dateChecker = async (payload: any) => {
|
||||||
|
await cyclesService
|
||||||
|
.cycleDateCheck(workspaceSlug as string, projectId as string, payload)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.status) {
|
||||||
|
setIsDateValid(true);
|
||||||
|
} else {
|
||||||
|
setIsDateValid(false);
|
||||||
|
setToastAlert({
|
||||||
|
type: "error",
|
||||||
|
title: "Error!",
|
||||||
|
message:
|
||||||
|
"You have a cycle already on the given dates, if you want to create your draft cycle you can do that by removing dates",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const checkEmptyDate =
|
||||||
|
(watch("start_date") === "" && watch("end_date") === "") ||
|
||||||
|
(watch("start_date") === null && watch("end_date") === null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
reset({
|
reset({
|
||||||
...defaultValues,
|
...defaultValues,
|
||||||
@ -84,30 +122,7 @@ export const CycleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, stat
|
|||||||
register={register}
|
register={register}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<h6 className="text-gray-500">Status</h6>
|
|
||||||
<Controller
|
|
||||||
name="status"
|
|
||||||
control={control}
|
|
||||||
render={({ field }) => (
|
|
||||||
<CustomSelect
|
|
||||||
{...field}
|
|
||||||
label={<span className="capitalize">{field.value ?? "Select Status"}</span>}
|
|
||||||
input
|
|
||||||
>
|
|
||||||
{[
|
|
||||||
{ label: "Draft", value: "draft" },
|
|
||||||
{ label: "Started", value: "started" },
|
|
||||||
{ label: "Completed", value: "completed" },
|
|
||||||
].map((item) => (
|
|
||||||
<CustomSelect.Option key={item.value} value={item.value}>
|
|
||||||
{item.label}
|
|
||||||
</CustomSelect.Option>
|
|
||||||
))}
|
|
||||||
</CustomSelect>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="flex gap-x-2">
|
<div className="flex gap-x-2">
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<h6 className="text-gray-500">Start Date</h6>
|
<h6 className="text-gray-500">Start Date</h6>
|
||||||
@ -115,12 +130,19 @@ export const CycleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, stat
|
|||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="start_date"
|
name="start_date"
|
||||||
rules={{ required: "Start date is required" }}
|
|
||||||
render={({ field: { value, onChange } }) => (
|
render={({ field: { value, onChange } }) => (
|
||||||
<CustomDatePicker
|
<CustomDatePicker
|
||||||
renderAs="input"
|
renderAs="input"
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={(val) => {
|
||||||
|
onChange(val);
|
||||||
|
watch("end_date")
|
||||||
|
? dateChecker({
|
||||||
|
start_date: val,
|
||||||
|
end_date: watch("end_date"),
|
||||||
|
})
|
||||||
|
: "";
|
||||||
|
}}
|
||||||
error={errors.start_date ? true : false}
|
error={errors.start_date ? true : false}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@ -136,12 +158,19 @@ export const CycleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, stat
|
|||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="end_date"
|
name="end_date"
|
||||||
rules={{ required: "End date is required" }}
|
|
||||||
render={({ field: { value, onChange } }) => (
|
render={({ field: { value, onChange } }) => (
|
||||||
<CustomDatePicker
|
<CustomDatePicker
|
||||||
renderAs="input"
|
renderAs="input"
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={(val) => {
|
||||||
|
onChange(val);
|
||||||
|
watch("start_date")
|
||||||
|
? dateChecker({
|
||||||
|
start_date: watch("start_date"),
|
||||||
|
end_date: val,
|
||||||
|
})
|
||||||
|
: "";
|
||||||
|
}}
|
||||||
error={errors.end_date ? true : false}
|
error={errors.end_date ? true : false}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@ -158,7 +187,18 @@ export const CycleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, stat
|
|||||||
<Button theme="secondary" onClick={handleClose}>
|
<Button theme="secondary" onClick={handleClose}>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="submit" disabled={isSubmitting}>
|
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
className={
|
||||||
|
checkEmptyDate
|
||||||
|
? "cursor-pointer"
|
||||||
|
: isDateValid
|
||||||
|
? "cursor-pointer"
|
||||||
|
: "cursor-not-allowed"
|
||||||
|
}
|
||||||
|
disabled={isSubmitting || checkEmptyDate ? false : isDateValid ? false : true}
|
||||||
|
>
|
||||||
{status
|
{status
|
||||||
? isSubmitting
|
? isSubmitting
|
||||||
? "Updating Cycle..."
|
? "Updating Cycle..."
|
||||||
|
@ -113,7 +113,7 @@ export const CreateUpdateCycleModal: React.FC<CycleModalProps> = ({
|
|||||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
>
|
>
|
||||||
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-white px-5 py-8 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
|
<Dialog.Panel className="relative transform rounded-lg bg-white px-5 py-8 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
|
||||||
<CycleForm
|
<CycleForm
|
||||||
handleFormSubmit={handleFormSubmit}
|
handleFormSubmit={handleFormSubmit}
|
||||||
handleClose={handleClose}
|
handleClose={handleClose}
|
||||||
|
Loading…
Reference in New Issue
Block a user