mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
fix : module and cycle invalid date fix (#605)
* fix: module and cycle modal invalid date validation * fix: cycle and module sidebar invalid date
This commit is contained in:
parent
a94e38c093
commit
f5f90dab69
@ -11,7 +11,7 @@ import useToast from "hooks/use-toast";
|
||||
// ui
|
||||
import { CustomDatePicker, Input, PrimaryButton, SecondaryButton, TextArea } from "components/ui";
|
||||
// helpers
|
||||
import { getDateRangeStatus } from "helpers/date-time.helper";
|
||||
import { getDateRangeStatus, isDateRangeValid } from "helpers/date-time.helper";
|
||||
// types
|
||||
import { ICycle } from "types";
|
||||
|
||||
@ -141,12 +141,22 @@ export const CycleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, stat
|
||||
value={value}
|
||||
onChange={(val) => {
|
||||
onChange(val);
|
||||
val && watch("end_date") && cycleStatus != "current"
|
||||
? dateChecker({
|
||||
start_date: val,
|
||||
end_date: watch("end_date"),
|
||||
})
|
||||
: "";
|
||||
if (val && watch("end_date")) {
|
||||
if (isDateRangeValid(val, `${watch("end_date")}`)) {
|
||||
cycleStatus != "current" &&
|
||||
dateChecker({
|
||||
start_date: val,
|
||||
end_date: watch("end_date"),
|
||||
});
|
||||
} else {
|
||||
setIsDateValid(false);
|
||||
setToastAlert({
|
||||
type: "error",
|
||||
title: "Error!",
|
||||
message: "You have enter invalid date.",
|
||||
});
|
||||
}
|
||||
}
|
||||
}}
|
||||
error={errors.start_date ? true : false}
|
||||
/>
|
||||
@ -169,12 +179,22 @@ export const CycleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, stat
|
||||
value={value}
|
||||
onChange={(val) => {
|
||||
onChange(val);
|
||||
val && watch("start_date") && cycleStatus != "current"
|
||||
? dateChecker({
|
||||
start_date: watch("start_date"),
|
||||
end_date: val,
|
||||
})
|
||||
: "";
|
||||
if (watch("start_date") && val) {
|
||||
if (isDateRangeValid(`${watch("start_date")}`, val)) {
|
||||
cycleStatus != "current" &&
|
||||
dateChecker({
|
||||
start_date: watch("start_date"),
|
||||
end_date: val,
|
||||
});
|
||||
} else {
|
||||
setIsDateValid(false);
|
||||
setToastAlert({
|
||||
type: "error",
|
||||
title: "Error!",
|
||||
message: "You have enter invalid date.",
|
||||
});
|
||||
}
|
||||
}
|
||||
}}
|
||||
error={errors.end_date ? true : false}
|
||||
/>
|
||||
|
@ -35,7 +35,7 @@ import { ExclamationIcon } from "components/icons";
|
||||
// helpers
|
||||
import { capitalizeFirstLetter, copyTextToClipboard } from "helpers/string.helper";
|
||||
import { groupBy } from "helpers/array.helper";
|
||||
import { renderDateFormat, renderShortDate } from "helpers/date-time.helper";
|
||||
import { isDateRangeValid, renderDateFormat, renderShortDate } from "helpers/date-time.helper";
|
||||
// types
|
||||
import { ICycle, IIssue } from "types";
|
||||
// fetch-keys
|
||||
@ -55,8 +55,6 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
||||
isCompleted,
|
||||
}) => {
|
||||
const [cycleDeleteModal, setCycleDeleteModal] = useState(false);
|
||||
const [startDateRange, setStartDateRange] = useState<Date | null>(new Date());
|
||||
const [endDateRange, setEndDateRange] = useState<Date | null>(null);
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, cycleId } = router.query;
|
||||
@ -89,7 +87,7 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
||||
...groupBy(issues ?? [], "state_detail.group"),
|
||||
};
|
||||
|
||||
const { reset } = useForm({
|
||||
const { reset, watch } = useForm({
|
||||
defaultValues,
|
||||
});
|
||||
|
||||
@ -190,17 +188,32 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
||||
>
|
||||
<Popover.Panel className="absolute top-10 -right-5 z-20 transform overflow-hidden">
|
||||
<DatePicker
|
||||
selected={startDateRange}
|
||||
selected={
|
||||
watch("start_date")
|
||||
? new Date(`${watch("start_date")}`)
|
||||
: new Date()
|
||||
}
|
||||
onChange={(date) => {
|
||||
submitChanges({
|
||||
start_date: renderDateFormat(date),
|
||||
});
|
||||
setStartDateRange(date);
|
||||
if (date && watch("end_date")) {
|
||||
if (
|
||||
isDateRangeValid(renderDateFormat(date), `${watch("end_date")}`)
|
||||
) {
|
||||
submitChanges({
|
||||
start_date: renderDateFormat(date),
|
||||
});
|
||||
} else {
|
||||
setToastAlert({
|
||||
type: "error",
|
||||
title: "Error!",
|
||||
message: "You have enter invalid date.",
|
||||
});
|
||||
}
|
||||
}
|
||||
}}
|
||||
selectsStart
|
||||
startDate={startDateRange}
|
||||
endDate={endDateRange}
|
||||
maxDate={endDateRange}
|
||||
startDate={new Date(`${watch("start_date")}`)}
|
||||
endDate={new Date(`${watch("end_date")}`)}
|
||||
maxDate={new Date(`${watch("end_date")}`)}
|
||||
shouldCloseOnSelect
|
||||
inline
|
||||
/>
|
||||
@ -237,18 +250,34 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
|
||||
>
|
||||
<Popover.Panel className="absolute top-10 -right-5 z-20 transform overflow-hidden">
|
||||
<DatePicker
|
||||
selected={endDateRange}
|
||||
selected={
|
||||
watch("end_date") ? new Date(`${watch("end_date")}`) : new Date()
|
||||
}
|
||||
onChange={(date) => {
|
||||
submitChanges({
|
||||
end_date: renderDateFormat(date),
|
||||
});
|
||||
setEndDateRange(date);
|
||||
if (watch("start_date") && date) {
|
||||
if (
|
||||
isDateRangeValid(
|
||||
`${watch("start_date")}`,
|
||||
renderDateFormat(date)
|
||||
)
|
||||
) {
|
||||
submitChanges({
|
||||
end_date: renderDateFormat(date),
|
||||
});
|
||||
} else {
|
||||
setToastAlert({
|
||||
type: "error",
|
||||
title: "Error!",
|
||||
message: "You have enter invalid date.",
|
||||
});
|
||||
}
|
||||
}
|
||||
}}
|
||||
selectsEnd
|
||||
startDate={startDateRange}
|
||||
endDate={endDateRange}
|
||||
// minDate={startDateRange}
|
||||
|
||||
startDate={new Date(`${watch("start_date")}`)}
|
||||
endDate={new Date(`${watch("end_date")}`)}
|
||||
minDate={new Date(`${watch("start_date")}`)}
|
||||
shouldCloseOnSelect
|
||||
inline
|
||||
/>
|
||||
</Popover.Panel>
|
||||
|
@ -1,11 +1,15 @@
|
||||
import { useEffect } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
// react-hook-form
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
// hooks
|
||||
import useToast from "hooks/use-toast";
|
||||
// components
|
||||
import { ModuleLeadSelect, ModuleMembersSelect, ModuleStatusSelect } from "components/modules";
|
||||
// ui
|
||||
import { CustomDatePicker, Input, PrimaryButton, SecondaryButton, TextArea } from "components/ui";
|
||||
// helper
|
||||
import { isDateRangeValid } from "helpers/date-time.helper";
|
||||
// types
|
||||
import { IModule } from "types";
|
||||
|
||||
@ -25,10 +29,13 @@ const defaultValues: Partial<IModule> = {
|
||||
};
|
||||
|
||||
export const ModuleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, status, data }) => {
|
||||
const [isDateValid, setIsDateValid] = useState(true);
|
||||
const { setToastAlert } = useToast();
|
||||
const {
|
||||
register,
|
||||
formState: { errors, isSubmitting },
|
||||
handleSubmit,
|
||||
watch,
|
||||
control,
|
||||
reset,
|
||||
} = useForm<IModule>({
|
||||
@ -94,7 +101,25 @@ export const ModuleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, sta
|
||||
control={control}
|
||||
name="start_date"
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<CustomDatePicker renderAs="input" value={value} onChange={onChange} />
|
||||
<CustomDatePicker
|
||||
renderAs="input"
|
||||
value={value}
|
||||
onChange={(val) => {
|
||||
onChange(val);
|
||||
if (val && watch("target_date")) {
|
||||
if (isDateRangeValid(val, `${watch("target_date")}`)) {
|
||||
setIsDateValid(true);
|
||||
} else {
|
||||
setIsDateValid(false);
|
||||
setToastAlert({
|
||||
type: "error",
|
||||
title: "Error!",
|
||||
message: "You have enter invalid date.",
|
||||
});
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
@ -106,7 +131,25 @@ export const ModuleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, sta
|
||||
control={control}
|
||||
name="target_date"
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<CustomDatePicker renderAs="input" value={value} onChange={onChange} />
|
||||
<CustomDatePicker
|
||||
renderAs="input"
|
||||
value={value}
|
||||
onChange={(val) => {
|
||||
onChange(val);
|
||||
if (watch("start_date") && val) {
|
||||
if (isDateRangeValid(`${watch("start_date")}`, val)) {
|
||||
setIsDateValid(true);
|
||||
} else {
|
||||
setIsDateValid(false);
|
||||
setToastAlert({
|
||||
type: "error",
|
||||
title: "Error!",
|
||||
message: "You have enter invalid date.",
|
||||
});
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
@ -133,7 +176,7 @@ export const ModuleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, sta
|
||||
</div>
|
||||
<div className="mt-5 flex justify-end gap-2">
|
||||
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
|
||||
<PrimaryButton type="submit" loading={isSubmitting}>
|
||||
<PrimaryButton type="submit" loading={isSubmitting || isDateValid ? false : true}>
|
||||
{status
|
||||
? isSubmitting
|
||||
? "Updating Module..."
|
||||
|
@ -32,7 +32,7 @@ import { CustomMenu, CustomSelect, Loader, ProgressBar } from "components/ui";
|
||||
// icon
|
||||
import { ExclamationIcon } from "components/icons";
|
||||
// helpers
|
||||
import { renderDateFormat, renderShortDate } from "helpers/date-time.helper";
|
||||
import { isDateRangeValid, renderDateFormat, renderShortDate } from "helpers/date-time.helper";
|
||||
import { capitalizeFirstLetter, copyTextToClipboard } from "helpers/string.helper";
|
||||
import { groupBy } from "helpers/array.helper";
|
||||
// types
|
||||
@ -67,8 +67,6 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({
|
||||
}) => {
|
||||
const [moduleDeleteModal, setModuleDeleteModal] = useState(false);
|
||||
const [moduleLinkModal, setModuleLinkModal] = useState(false);
|
||||
const [startDateRange, setStartDateRange] = useState<Date | null>(new Date());
|
||||
const [endDateRange, setEndDateRange] = useState<Date | null>(null);
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, moduleId } = router.query;
|
||||
@ -257,17 +255,20 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({
|
||||
>
|
||||
<Popover.Panel className="absolute top-10 -right-5 z-20 transform overflow-hidden">
|
||||
<DatePicker
|
||||
selected={startDateRange}
|
||||
selected={
|
||||
watch("start_date")
|
||||
? new Date(`${watch("start_date")}`)
|
||||
: new Date()
|
||||
}
|
||||
onChange={(date) => {
|
||||
submitChanges({
|
||||
start_date: renderDateFormat(date),
|
||||
});
|
||||
setStartDateRange(date);
|
||||
}}
|
||||
selectsStart
|
||||
startDate={startDateRange}
|
||||
endDate={endDateRange}
|
||||
maxDate={endDateRange}
|
||||
startDate={new Date(`${watch("start_date")}`)}
|
||||
endDate={new Date(`${watch("target_date")}`)}
|
||||
maxDate={new Date(`${watch("target_date")}`)}
|
||||
shouldCloseOnSelect
|
||||
inline
|
||||
/>
|
||||
@ -303,18 +304,19 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({
|
||||
>
|
||||
<Popover.Panel className="absolute top-10 -right-5 z-20 transform overflow-hidden">
|
||||
<DatePicker
|
||||
selected={endDateRange}
|
||||
selected={
|
||||
watch("target_date") ? new Date(`${watch("target_date")}`) : new Date()
|
||||
}
|
||||
onChange={(date) => {
|
||||
submitChanges({
|
||||
target_date: renderDateFormat(date),
|
||||
});
|
||||
setEndDateRange(date);
|
||||
}}
|
||||
selectsEnd
|
||||
startDate={startDateRange}
|
||||
endDate={endDateRange}
|
||||
// minDate={startDateRange}
|
||||
|
||||
startDate={new Date(`${watch("start_date")}`)}
|
||||
endDate={new Date(`${watch("target_date")}`)}
|
||||
minDate={new Date(`${watch("start_date")}`)}
|
||||
shouldCloseOnSelect
|
||||
inline
|
||||
/>
|
||||
</Popover.Panel>
|
||||
|
@ -169,3 +169,5 @@ export const renderShortTime = (date: string | Date) => {
|
||||
|
||||
return hours + ":" + minutes;
|
||||
};
|
||||
|
||||
export const isDateRangeValid = (startDate: string, endDate: string)=> new Date(startDate) < new Date(endDate);
|
Loading…
Reference in New Issue
Block a user