Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions apps/app/components/cycles/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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(() => {
Expand All @@ -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">
Expand Down Expand Up @@ -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>
Expand All @@ -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>
Expand Down
104 changes: 33 additions & 71 deletions apps/app/components/cycles/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -121,8 +120,6 @@ export const CreateUpdateCycleModal: React.FC<CycleModalProps> = ({
}
}

handleClose();

setToastAlert({
type: "success",
title: "Success!",
Expand All @@ -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>) => {
Expand All @@ -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({
start_date: payload.start_date,
end_date: payload.end_date,
});

if (isDateValid) {
if (data) {
await updateCycle(data.id, payload);
} else {
await createCycle(payload);
}
} 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",
else
isDateValid = await dateChecker({
start_date: payload.start_date,
end_date: payload.end_date,
});
handleClose();
}
} else {
if (data) {
await updateCycle(data.id, payload);
} else {
await createCycle(payload);
}
}

if (isDateValid) {
if (data) await updateCycle(data.id, payload);
else await createCycle(payload);

handleClose();
} else
setToastAlert({
type: "error",
title: "Error!",
message:
"You already have a cycle on the given dates, if you want to create a draft cycle, remove the dates.",
});
};

return (
Expand Down
31 changes: 16 additions & 15 deletions apps/app/components/issues/activity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) => (
<>
added a new assignee{" "}
<span className="font-medium text-custom-text-100">{activity.new_value}</span>.
</>
),
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: {
Expand Down
18 changes: 16 additions & 2 deletions apps/app/components/ui/date.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down Expand Up @@ -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>
Expand Down
7 changes: 2 additions & 5 deletions apps/app/services/cycles.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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/`,
Expand Down
6 changes: 6 additions & 0 deletions apps/app/types/cycles.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};