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:
Anmol Singh Bhatia 2023-03-30 16:00:48 +05:30 committed by GitHub
parent a94e38c093
commit f5f90dab69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 148 additions and 52 deletions

View File

@ -11,7 +11,7 @@ import useToast from "hooks/use-toast";
// ui // ui
import { CustomDatePicker, Input, PrimaryButton, SecondaryButton, TextArea } from "components/ui"; import { CustomDatePicker, Input, PrimaryButton, SecondaryButton, TextArea } from "components/ui";
// helpers // helpers
import { getDateRangeStatus } from "helpers/date-time.helper"; import { getDateRangeStatus, isDateRangeValid } from "helpers/date-time.helper";
// types // types
import { ICycle } from "types"; import { ICycle } from "types";
@ -141,12 +141,22 @@ export const CycleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, stat
value={value} value={value}
onChange={(val) => { onChange={(val) => {
onChange(val); onChange(val);
val && watch("end_date") && cycleStatus != "current" if (val && watch("end_date")) {
? dateChecker({ if (isDateRangeValid(val, `${watch("end_date")}`)) {
start_date: val, cycleStatus != "current" &&
end_date: watch("end_date"), 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} error={errors.start_date ? true : false}
/> />
@ -169,12 +179,22 @@ export const CycleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, stat
value={value} value={value}
onChange={(val) => { onChange={(val) => {
onChange(val); onChange(val);
val && watch("start_date") && cycleStatus != "current" if (watch("start_date") && val) {
? dateChecker({ if (isDateRangeValid(`${watch("start_date")}`, val)) {
start_date: watch("start_date"), cycleStatus != "current" &&
end_date: val, 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} error={errors.end_date ? true : false}
/> />

View File

@ -35,7 +35,7 @@ import { ExclamationIcon } from "components/icons";
// helpers // helpers
import { capitalizeFirstLetter, copyTextToClipboard } from "helpers/string.helper"; import { capitalizeFirstLetter, copyTextToClipboard } from "helpers/string.helper";
import { groupBy } from "helpers/array.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 // types
import { ICycle, IIssue } from "types"; import { ICycle, IIssue } from "types";
// fetch-keys // fetch-keys
@ -55,8 +55,6 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
isCompleted, isCompleted,
}) => { }) => {
const [cycleDeleteModal, setCycleDeleteModal] = useState(false); const [cycleDeleteModal, setCycleDeleteModal] = useState(false);
const [startDateRange, setStartDateRange] = useState<Date | null>(new Date());
const [endDateRange, setEndDateRange] = useState<Date | null>(null);
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, cycleId } = router.query; const { workspaceSlug, projectId, cycleId } = router.query;
@ -89,7 +87,7 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
...groupBy(issues ?? [], "state_detail.group"), ...groupBy(issues ?? [], "state_detail.group"),
}; };
const { reset } = useForm({ const { reset, watch } = useForm({
defaultValues, defaultValues,
}); });
@ -190,17 +188,32 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
> >
<Popover.Panel className="absolute top-10 -right-5 z-20 transform overflow-hidden"> <Popover.Panel className="absolute top-10 -right-5 z-20 transform overflow-hidden">
<DatePicker <DatePicker
selected={startDateRange} selected={
watch("start_date")
? new Date(`${watch("start_date")}`)
: new Date()
}
onChange={(date) => { onChange={(date) => {
submitChanges({ if (date && watch("end_date")) {
start_date: renderDateFormat(date), if (
}); isDateRangeValid(renderDateFormat(date), `${watch("end_date")}`)
setStartDateRange(date); ) {
submitChanges({
start_date: renderDateFormat(date),
});
} else {
setToastAlert({
type: "error",
title: "Error!",
message: "You have enter invalid date.",
});
}
}
}} }}
selectsStart selectsStart
startDate={startDateRange} startDate={new Date(`${watch("start_date")}`)}
endDate={endDateRange} endDate={new Date(`${watch("end_date")}`)}
maxDate={endDateRange} maxDate={new Date(`${watch("end_date")}`)}
shouldCloseOnSelect shouldCloseOnSelect
inline inline
/> />
@ -237,18 +250,34 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
> >
<Popover.Panel className="absolute top-10 -right-5 z-20 transform overflow-hidden"> <Popover.Panel className="absolute top-10 -right-5 z-20 transform overflow-hidden">
<DatePicker <DatePicker
selected={endDateRange} selected={
watch("end_date") ? new Date(`${watch("end_date")}`) : new Date()
}
onChange={(date) => { onChange={(date) => {
submitChanges({ if (watch("start_date") && date) {
end_date: renderDateFormat(date), if (
}); isDateRangeValid(
setEndDateRange(date); `${watch("start_date")}`,
renderDateFormat(date)
)
) {
submitChanges({
end_date: renderDateFormat(date),
});
} else {
setToastAlert({
type: "error",
title: "Error!",
message: "You have enter invalid date.",
});
}
}
}} }}
selectsEnd selectsEnd
startDate={startDateRange} startDate={new Date(`${watch("start_date")}`)}
endDate={endDateRange} endDate={new Date(`${watch("end_date")}`)}
// minDate={startDateRange} minDate={new Date(`${watch("start_date")}`)}
shouldCloseOnSelect
inline inline
/> />
</Popover.Panel> </Popover.Panel>

View File

@ -1,11 +1,15 @@
import { useEffect } from "react"; import { useEffect, useState } from "react";
// react-hook-form // react-hook-form
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
// hooks
import useToast from "hooks/use-toast";
// components // components
import { ModuleLeadSelect, ModuleMembersSelect, ModuleStatusSelect } from "components/modules"; import { ModuleLeadSelect, ModuleMembersSelect, ModuleStatusSelect } from "components/modules";
// ui // ui
import { CustomDatePicker, Input, PrimaryButton, SecondaryButton, TextArea } from "components/ui"; import { CustomDatePicker, Input, PrimaryButton, SecondaryButton, TextArea } from "components/ui";
// helper
import { isDateRangeValid } from "helpers/date-time.helper";
// types // types
import { IModule } from "types"; import { IModule } from "types";
@ -25,10 +29,13 @@ const defaultValues: Partial<IModule> = {
}; };
export const ModuleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, status, data }) => { export const ModuleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, status, data }) => {
const [isDateValid, setIsDateValid] = useState(true);
const { setToastAlert } = useToast();
const { const {
register, register,
formState: { errors, isSubmitting }, formState: { errors, isSubmitting },
handleSubmit, handleSubmit,
watch,
control, control,
reset, reset,
} = useForm<IModule>({ } = useForm<IModule>({
@ -94,7 +101,25 @@ export const ModuleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, sta
control={control} control={control}
name="start_date" name="start_date"
render={({ field: { value, onChange } }) => ( 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> </div>
@ -106,7 +131,25 @@ export const ModuleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, sta
control={control} control={control}
name="target_date" name="target_date"
render={({ field: { value, onChange } }) => ( 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> </div>
@ -133,7 +176,7 @@ export const ModuleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, sta
</div> </div>
<div className="mt-5 flex justify-end gap-2"> <div className="mt-5 flex justify-end gap-2">
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton> <SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<PrimaryButton type="submit" loading={isSubmitting}> <PrimaryButton type="submit" loading={isSubmitting || isDateValid ? false : true}>
{status {status
? isSubmitting ? isSubmitting
? "Updating Module..." ? "Updating Module..."

View File

@ -32,7 +32,7 @@ import { CustomMenu, CustomSelect, Loader, ProgressBar } from "components/ui";
// icon // icon
import { ExclamationIcon } from "components/icons"; import { ExclamationIcon } from "components/icons";
// helpers // 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 { capitalizeFirstLetter, copyTextToClipboard } from "helpers/string.helper";
import { groupBy } from "helpers/array.helper"; import { groupBy } from "helpers/array.helper";
// types // types
@ -67,8 +67,6 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({
}) => { }) => {
const [moduleDeleteModal, setModuleDeleteModal] = useState(false); const [moduleDeleteModal, setModuleDeleteModal] = useState(false);
const [moduleLinkModal, setModuleLinkModal] = 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 router = useRouter();
const { workspaceSlug, projectId, moduleId } = router.query; 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"> <Popover.Panel className="absolute top-10 -right-5 z-20 transform overflow-hidden">
<DatePicker <DatePicker
selected={startDateRange} selected={
watch("start_date")
? new Date(`${watch("start_date")}`)
: new Date()
}
onChange={(date) => { onChange={(date) => {
submitChanges({ submitChanges({
start_date: renderDateFormat(date), start_date: renderDateFormat(date),
}); });
setStartDateRange(date);
}} }}
selectsStart selectsStart
startDate={startDateRange} startDate={new Date(`${watch("start_date")}`)}
endDate={endDateRange} endDate={new Date(`${watch("target_date")}`)}
maxDate={endDateRange} maxDate={new Date(`${watch("target_date")}`)}
shouldCloseOnSelect shouldCloseOnSelect
inline inline
/> />
@ -303,18 +304,19 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({
> >
<Popover.Panel className="absolute top-10 -right-5 z-20 transform overflow-hidden"> <Popover.Panel className="absolute top-10 -right-5 z-20 transform overflow-hidden">
<DatePicker <DatePicker
selected={endDateRange} selected={
watch("target_date") ? new Date(`${watch("target_date")}`) : new Date()
}
onChange={(date) => { onChange={(date) => {
submitChanges({ submitChanges({
target_date: renderDateFormat(date), target_date: renderDateFormat(date),
}); });
setEndDateRange(date);
}} }}
selectsEnd selectsEnd
startDate={startDateRange} startDate={new Date(`${watch("start_date")}`)}
endDate={endDateRange} endDate={new Date(`${watch("target_date")}`)}
// minDate={startDateRange} minDate={new Date(`${watch("start_date")}`)}
shouldCloseOnSelect
inline inline
/> />
</Popover.Panel> </Popover.Panel>

View File

@ -169,3 +169,5 @@ export const renderShortTime = (date: string | Date) => {
return hours + ":" + minutes; return hours + ":" + minutes;
}; };
export const isDateRangeValid = (startDate: string, endDate: string)=> new Date(startDate) < new Date(endDate);