forked from github/plane
fix: create cycle modal (#1631)
* fix: cycle date select in the modal * chore: update remove assignee issue activity
This commit is contained in:
parent
464c13fcd0
commit
fe60771943
@ -29,16 +29,13 @@ export const CycleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, stat
|
||||
handleSubmit,
|
||||
control,
|
||||
reset,
|
||||
watch,
|
||||
} = useForm<ICycle>({
|
||||
defaultValues,
|
||||
});
|
||||
|
||||
const handleCreateUpdateCycle = async (formData: Partial<ICycle>) => {
|
||||
await handleFormSubmit(formData);
|
||||
|
||||
reset({
|
||||
...defaultValues,
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@ -48,6 +45,15 @@ export const CycleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, stat
|
||||
});
|
||||
}, [data, reset]);
|
||||
|
||||
const startDate = watch("start_date");
|
||||
const endDate = watch("end_date");
|
||||
|
||||
const minDate = startDate ? new Date(startDate) : new Date();
|
||||
minDate.setDate(minDate.getDate() + 1);
|
||||
|
||||
const maxDate = endDate ? new Date(endDate) : null;
|
||||
maxDate?.setDate(maxDate.getDate() - 1);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(handleCreateUpdateCycle)}>
|
||||
<div className="space-y-5">
|
||||
@ -91,7 +97,13 @@ export const CycleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, stat
|
||||
control={control}
|
||||
name="start_date"
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<DateSelect label="Start date" value={value} onChange={(val) => onChange(val)} />
|
||||
<DateSelect
|
||||
label="Start date"
|
||||
value={value}
|
||||
onChange={(val) => onChange(val)}
|
||||
minDate={new Date()}
|
||||
maxDate={maxDate ?? undefined}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
@ -100,7 +112,12 @@ export const CycleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, stat
|
||||
control={control}
|
||||
name="end_date"
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<DateSelect label="End date" value={value} onChange={(val) => onChange(val)} />
|
||||
<DateSelect
|
||||
label="End date"
|
||||
value={value}
|
||||
onChange={(val) => onChange(val)}
|
||||
minDate={minDate}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
@ -13,9 +13,9 @@ import useToast from "hooks/use-toast";
|
||||
// components
|
||||
import { CycleForm } from "components/cycles";
|
||||
// helper
|
||||
import { getDateRangeStatus, isDateGreaterThanToday } from "helpers/date-time.helper";
|
||||
import { getDateRangeStatus } from "helpers/date-time.helper";
|
||||
// types
|
||||
import type { ICurrentUserResponse, ICycle } from "types";
|
||||
import type { CycleDateCheckData, ICurrentUserResponse, ICycle } from "types";
|
||||
// fetch keys
|
||||
import {
|
||||
COMPLETED_CYCLES_LIST,
|
||||
@ -65,7 +65,6 @@ export const CreateUpdateCycleModal: React.FC<CycleModalProps> = ({
|
||||
}
|
||||
mutate(INCOMPLETE_CYCLES_LIST(projectId.toString()));
|
||||
mutate(CYCLES_LIST(projectId.toString()));
|
||||
handleClose();
|
||||
|
||||
setToastAlert({
|
||||
type: "success",
|
||||
@ -121,8 +120,6 @@ export const CreateUpdateCycleModal: React.FC<CycleModalProps> = ({
|
||||
}
|
||||
}
|
||||
|
||||
handleClose();
|
||||
|
||||
setToastAlert({
|
||||
type: "success",
|
||||
title: "Success!",
|
||||
@ -138,19 +135,16 @@ export const CreateUpdateCycleModal: React.FC<CycleModalProps> = ({
|
||||
});
|
||||
};
|
||||
|
||||
const dateChecker = async (payload: any) => {
|
||||
try {
|
||||
const res = await cycleService.cycleDateCheck(
|
||||
workspaceSlug as string,
|
||||
projectId as string,
|
||||
payload
|
||||
);
|
||||
console.log(res);
|
||||
return res.status;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return false;
|
||||
}
|
||||
const dateChecker = async (payload: CycleDateCheckData) => {
|
||||
let status = false;
|
||||
|
||||
await cycleService
|
||||
.cycleDateCheck(workspaceSlug as string, projectId as string, payload)
|
||||
.then((res) => {
|
||||
status = res.status;
|
||||
});
|
||||
|
||||
return status;
|
||||
};
|
||||
|
||||
const handleFormSubmit = async (formData: Partial<ICycle>) => {
|
||||
@ -160,66 +154,34 @@ export const CreateUpdateCycleModal: React.FC<CycleModalProps> = ({
|
||||
...formData,
|
||||
};
|
||||
|
||||
if (payload.start_date && payload.end_date) {
|
||||
if (!isDateGreaterThanToday(payload.end_date)) {
|
||||
setToastAlert({
|
||||
type: "error",
|
||||
title: "Error!",
|
||||
message: "Unable to create cycle in past date. Please enter a valid date.",
|
||||
});
|
||||
handleClose();
|
||||
return;
|
||||
}
|
||||
let isDateValid: boolean = true;
|
||||
|
||||
if (data?.start_date && data?.end_date) {
|
||||
const isDateValidForExistingCycle = await dateChecker({
|
||||
if (payload.start_date && payload.end_date) {
|
||||
if (data?.start_date && data?.end_date)
|
||||
isDateValid = await dateChecker({
|
||||
start_date: payload.start_date,
|
||||
end_date: payload.end_date,
|
||||
cycle_id: data.id,
|
||||
});
|
||||
|
||||
if (isDateValidForExistingCycle) {
|
||||
await updateCycle(data.id, payload);
|
||||
return;
|
||||
} else {
|
||||
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",
|
||||
});
|
||||
handleClose();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const isDateValid = await dateChecker({
|
||||
else
|
||||
isDateValid = await dateChecker({
|
||||
start_date: payload.start_date,
|
||||
end_date: payload.end_date,
|
||||
});
|
||||
}
|
||||
|
||||
if (isDateValid) {
|
||||
if (data) {
|
||||
await updateCycle(data.id, payload);
|
||||
} else {
|
||||
await createCycle(payload);
|
||||
}
|
||||
} else {
|
||||
if (data) await updateCycle(data.id, payload);
|
||||
else await createCycle(payload);
|
||||
|
||||
handleClose();
|
||||
} else
|
||||
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",
|
||||
"You already have a cycle on the given dates, if you want to create a draft cycle, remove the dates.",
|
||||
});
|
||||
handleClose();
|
||||
}
|
||||
} else {
|
||||
if (data) {
|
||||
await updateCycle(data.id, payload);
|
||||
} else {
|
||||
await createCycle(payload);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -27,22 +27,23 @@ const activityDetails: {
|
||||
icon: React.ReactNode;
|
||||
};
|
||||
} = {
|
||||
assignee: {
|
||||
message: (activity) => (
|
||||
<>
|
||||
removed the assignee{" "}
|
||||
<span className="font-medium text-custom-text-100">{activity.old_value}</span>.
|
||||
</>
|
||||
),
|
||||
icon: <Icon iconName="group" className="!text-sm" aria-hidden="true" />,
|
||||
},
|
||||
assignees: {
|
||||
message: (activity) => (
|
||||
message: (activity) => {
|
||||
if (activity.old_value === "")
|
||||
return (
|
||||
<>
|
||||
added a new assignee{" "}
|
||||
<span className="font-medium text-custom-text-100">{activity.new_value}</span>.
|
||||
</>
|
||||
),
|
||||
);
|
||||
else
|
||||
return (
|
||||
<>
|
||||
removed the assignee{" "}
|
||||
<span className="font-medium text-custom-text-100">{activity.old_value}</span>.
|
||||
</>
|
||||
);
|
||||
},
|
||||
icon: <Icon iconName="group" className="!text-sm" aria-hidden="true" />,
|
||||
},
|
||||
archived_at: {
|
||||
|
@ -11,11 +11,21 @@ type Props = {
|
||||
value: string | null;
|
||||
onChange: (val: string | null) => void;
|
||||
label: string;
|
||||
minDate?: Date;
|
||||
maxDate?: Date;
|
||||
closeOnSelect?: boolean;
|
||||
};
|
||||
|
||||
export const DateSelect: React.FC<Props> = ({ value, onChange, label }) => (
|
||||
export const DateSelect: React.FC<Props> = ({
|
||||
value,
|
||||
onChange,
|
||||
label,
|
||||
minDate,
|
||||
maxDate,
|
||||
closeOnSelect = true,
|
||||
}) => (
|
||||
<Popover className="relative flex items-center justify-center rounded-lg">
|
||||
{({ open }) => (
|
||||
{({ close }) => (
|
||||
<>
|
||||
<Popover.Button className="flex cursor-pointer items-center rounded-md border border-custom-border-200 text-xs shadow-sm duration-300 hover:bg-custom-background-80">
|
||||
<span className="flex items-center justify-center gap-2 px-2 py-1 text-xs text-custom-text-200">
|
||||
@ -50,8 +60,12 @@ export const DateSelect: React.FC<Props> = ({ value, onChange, label }) => (
|
||||
onChange={(val) => {
|
||||
if (!val) onChange("");
|
||||
else onChange(renderDateFormat(val));
|
||||
|
||||
if (closeOnSelect) close();
|
||||
}}
|
||||
dateFormat="dd-MM-yyyy"
|
||||
minDate={minDate}
|
||||
maxDate={maxDate}
|
||||
inline
|
||||
/>
|
||||
</Popover.Panel>
|
||||
|
@ -3,7 +3,7 @@ import APIService from "services/api.service";
|
||||
import trackEventServices from "services/track-event.service";
|
||||
|
||||
// types
|
||||
import type { ICurrentUserResponse, ICycle, IIssue, IIssueViewOptions } from "types";
|
||||
import type { CycleDateCheckData, ICurrentUserResponse, ICycle, IIssue } from "types";
|
||||
|
||||
const { NEXT_PUBLIC_API_BASE_URL } = process.env;
|
||||
|
||||
@ -148,10 +148,7 @@ class ProjectCycleServices extends APIService {
|
||||
async cycleDateCheck(
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
data: {
|
||||
start_date: string;
|
||||
end_date: string;
|
||||
}
|
||||
data: CycleDateCheckData
|
||||
): Promise<any> {
|
||||
return this.post(
|
||||
`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/date-check/`,
|
||||
|
6
apps/app/types/cycles.d.ts
vendored
6
apps/app/types/cycles.d.ts
vendored
@ -85,3 +85,9 @@ export type SelectCycleType =
|
||||
| undefined;
|
||||
|
||||
export type SelectIssue = (IIssue & { actionType: "edit" | "delete" | "create" }) | null;
|
||||
|
||||
export type CycleDateCheckData = {
|
||||
start_date: string;
|
||||
end_date: string;
|
||||
cycle_id?: string;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user