mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
fix: calendar view mutation (#1042)
This commit is contained in:
parent
dbbd9add99
commit
290318603d
@ -1,4 +1,17 @@
|
||||
import React from "react";
|
||||
|
||||
// headless ui
|
||||
import { Popover, Transition } from "@headlessui/react";
|
||||
// ui
|
||||
import { CustomMenu, ToggleSwitch } from "components/ui";
|
||||
// icons
|
||||
import {
|
||||
CheckIcon,
|
||||
ChevronDownIcon,
|
||||
ChevronLeftIcon,
|
||||
ChevronRightIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
// helpers
|
||||
import {
|
||||
addMonths,
|
||||
addSevenDaysToDate,
|
||||
@ -14,26 +27,17 @@ import {
|
||||
updateDateWithMonth,
|
||||
updateDateWithYear,
|
||||
} from "helpers/calendar.helper";
|
||||
import React from "react";
|
||||
// constants
|
||||
import { MONTHS_LIST, YEARS_LIST } from "constants/calendar";
|
||||
|
||||
import { ICalendarRange } from "types";
|
||||
import {
|
||||
CheckIcon,
|
||||
ChevronDownIcon,
|
||||
ChevronLeftIcon,
|
||||
ChevronRightIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { CustomMenu, ToggleSwitch } from "components/ui";
|
||||
|
||||
type Props = {
|
||||
isMonthlyView: boolean;
|
||||
setIsMonthlyView: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
currentDate: Date;
|
||||
setCurrentDate: React.Dispatch<React.SetStateAction<Date>>;
|
||||
setCalendarDateRange: React.Dispatch<React.SetStateAction<ICalendarRange>>;
|
||||
showWeekEnds: boolean;
|
||||
setShowWeekEnds: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
changeDateRange: (startDate: Date, endDate: Date) => void;
|
||||
};
|
||||
|
||||
export const CalendarHeader: React.FC<Props> = ({
|
||||
@ -41,18 +45,16 @@ export const CalendarHeader: React.FC<Props> = ({
|
||||
isMonthlyView,
|
||||
currentDate,
|
||||
setCurrentDate,
|
||||
setCalendarDateRange,
|
||||
showWeekEnds,
|
||||
setShowWeekEnds,
|
||||
changeDateRange,
|
||||
}) => {
|
||||
const updateDate = (date: Date) => {
|
||||
setCurrentDate(date);
|
||||
|
||||
setCalendarDateRange({
|
||||
startDate: startOfWeek(date),
|
||||
endDate: lastDayOfWeek(date),
|
||||
});
|
||||
changeDateRange(startOfWeek(date), lastDayOfWeek(date));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<div className="relative flex h-full w-full items-center justify-start gap-2 text-sm ">
|
||||
@ -93,9 +95,13 @@ export const CalendarHeader: React.FC<Props> = ({
|
||||
<div className="grid grid-cols-4 border-t border-brand-base px-2">
|
||||
{MONTHS_LIST.map((month) => (
|
||||
<button
|
||||
onClick={() => updateDate(updateDateWithMonth(`${month.value}`, currentDate))}
|
||||
onClick={() =>
|
||||
updateDate(updateDateWithMonth(`${month.value}`, currentDate))
|
||||
}
|
||||
className={`px-2 py-2 text-xs text-brand-secondary hover:font-medium hover:text-brand-base ${
|
||||
isSameMonth(`${month.value}`, currentDate) ? "font-medium text-brand-base" : ""
|
||||
isSameMonth(`${month.value}`, currentDate)
|
||||
? "font-medium text-brand-base"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
{month.label}
|
||||
@ -116,10 +122,10 @@ export const CalendarHeader: React.FC<Props> = ({
|
||||
updateDate(subtractMonths(currentDate, 1));
|
||||
} else {
|
||||
setCurrentDate(subtract7DaysToDate(currentDate));
|
||||
setCalendarDateRange({
|
||||
startDate: getCurrentWeekStartDate(subtract7DaysToDate(currentDate)),
|
||||
endDate: getCurrentWeekEndDate(subtract7DaysToDate(currentDate)),
|
||||
});
|
||||
changeDateRange(
|
||||
getCurrentWeekStartDate(subtract7DaysToDate(currentDate)),
|
||||
getCurrentWeekEndDate(subtract7DaysToDate(currentDate))
|
||||
);
|
||||
}
|
||||
}}
|
||||
>
|
||||
@ -132,10 +138,10 @@ export const CalendarHeader: React.FC<Props> = ({
|
||||
updateDate(addMonths(currentDate, 1));
|
||||
} else {
|
||||
setCurrentDate(addSevenDaysToDate(currentDate));
|
||||
setCalendarDateRange({
|
||||
startDate: getCurrentWeekStartDate(addSevenDaysToDate(currentDate)),
|
||||
endDate: getCurrentWeekEndDate(addSevenDaysToDate(currentDate)),
|
||||
});
|
||||
changeDateRange(
|
||||
getCurrentWeekStartDate(addSevenDaysToDate(currentDate)),
|
||||
getCurrentWeekEndDate(addSevenDaysToDate(currentDate))
|
||||
);
|
||||
}
|
||||
}}
|
||||
>
|
||||
@ -152,10 +158,10 @@ export const CalendarHeader: React.FC<Props> = ({
|
||||
updateDate(new Date());
|
||||
} else {
|
||||
setCurrentDate(new Date());
|
||||
setCalendarDateRange({
|
||||
startDate: getCurrentWeekStartDate(new Date()),
|
||||
endDate: getCurrentWeekEndDate(new Date()),
|
||||
});
|
||||
changeDateRange(
|
||||
getCurrentWeekStartDate(new Date()),
|
||||
getCurrentWeekEndDate(new Date())
|
||||
);
|
||||
}
|
||||
}}
|
||||
>
|
||||
@ -173,10 +179,7 @@ export const CalendarHeader: React.FC<Props> = ({
|
||||
<CustomMenu.MenuItem
|
||||
onClick={() => {
|
||||
setIsMonthlyView(true);
|
||||
setCalendarDateRange({
|
||||
startDate: startOfWeek(currentDate),
|
||||
endDate: lastDayOfWeek(currentDate),
|
||||
});
|
||||
changeDateRange(startOfWeek(currentDate), lastDayOfWeek(currentDate));
|
||||
}}
|
||||
className="w-52 text-sm text-brand-secondary"
|
||||
>
|
||||
@ -190,10 +193,10 @@ export const CalendarHeader: React.FC<Props> = ({
|
||||
<CustomMenu.MenuItem
|
||||
onClick={() => {
|
||||
setIsMonthlyView(false);
|
||||
setCalendarDateRange({
|
||||
startDate: getCurrentWeekStartDate(currentDate),
|
||||
endDate: getCurrentWeekEndDate(currentDate),
|
||||
});
|
||||
changeDateRange(
|
||||
getCurrentWeekStartDate(currentDate),
|
||||
getCurrentWeekEndDate(currentDate)
|
||||
);
|
||||
}}
|
||||
className="w-52 text-sm text-brand-secondary"
|
||||
>
|
||||
|
@ -1,28 +1,20 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
// swr
|
||||
import useSWR, { mutate } from "swr";
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
// ui
|
||||
import { DragDropContext, Draggable, DropResult } from "react-beautiful-dnd";
|
||||
import { SingleCalendarDate, CalendarHeader } from "components/core";
|
||||
import { mutate } from "swr";
|
||||
|
||||
import { Spinner } from "components/ui";
|
||||
// hooks
|
||||
import useIssuesView from "hooks/use-issues-view";
|
||||
// react-beautiful-dnd
|
||||
import { DragDropContext, DropResult } from "react-beautiful-dnd";
|
||||
// services
|
||||
import issuesService from "services/issues.service";
|
||||
import cyclesService from "services/cycles.service";
|
||||
import modulesService from "services/modules.service";
|
||||
// fetch key
|
||||
import {
|
||||
CYCLE_CALENDAR_ISSUES,
|
||||
MODULE_CALENDAR_ISSUES,
|
||||
PROJECT_CALENDAR_ISSUES,
|
||||
} from "constants/fetch-keys";
|
||||
// helper
|
||||
// hooks
|
||||
import useCalendarIssuesView from "hooks/use-calendar-issues-view";
|
||||
// components
|
||||
import { SingleCalendarDate, CalendarHeader } from "components/core";
|
||||
// ui
|
||||
import { Spinner } from "components/ui";
|
||||
// helpers
|
||||
import { renderDateFormat } from "helpers/date-time.helper";
|
||||
import {
|
||||
startOfWeek,
|
||||
@ -31,8 +23,15 @@ import {
|
||||
weekDayInterval,
|
||||
formatDate,
|
||||
} from "helpers/calendar.helper";
|
||||
// type
|
||||
// types
|
||||
import { ICalendarRange, IIssue, UserAuth } from "types";
|
||||
// fetch-keys
|
||||
import {
|
||||
CYCLE_ISSUES_WITH_PARAMS,
|
||||
MODULE_ISSUES_WITH_PARAMS,
|
||||
PROJECT_ISSUES_LIST_WITH_PARAMS,
|
||||
VIEW_ISSUES,
|
||||
} from "constants/fetch-keys";
|
||||
|
||||
type Props = {
|
||||
handleEditIssue: (issue: IIssue) => void;
|
||||
@ -53,93 +52,31 @@ export const CalendarView: React.FC<Props> = ({
|
||||
const [currentDate, setCurrentDate] = useState(new Date());
|
||||
const [isMonthlyView, setIsMonthlyView] = useState(true);
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
||||
|
||||
const { params } = useIssuesView();
|
||||
|
||||
const [calendarDateRange, setCalendarDateRange] = useState<ICalendarRange>({
|
||||
const [calendarDates, setCalendarDates] = useState<ICalendarRange>({
|
||||
startDate: startOfWeek(currentDate),
|
||||
endDate: lastDayOfWeek(currentDate),
|
||||
});
|
||||
|
||||
const { data: projectCalendarIssues } = useSWR(
|
||||
workspaceSlug && projectId ? PROJECT_CALENDAR_ISSUES(projectId as string) : null,
|
||||
workspaceSlug && projectId
|
||||
? () =>
|
||||
issuesService.getIssuesWithParams(workspaceSlug as string, projectId as string, {
|
||||
...params,
|
||||
target_date: `${renderDateFormat(calendarDateRange.startDate)};after,${renderDateFormat(
|
||||
calendarDateRange.endDate
|
||||
)};before`,
|
||||
group_by: null,
|
||||
})
|
||||
: null
|
||||
);
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;
|
||||
|
||||
const { data: cycleCalendarIssues } = useSWR(
|
||||
workspaceSlug && projectId && cycleId
|
||||
? CYCLE_CALENDAR_ISSUES(projectId as string, cycleId as string)
|
||||
: null,
|
||||
workspaceSlug && projectId && cycleId
|
||||
? () =>
|
||||
cyclesService.getCycleIssuesWithParams(
|
||||
workspaceSlug as string,
|
||||
projectId as string,
|
||||
cycleId as string,
|
||||
{
|
||||
...params,
|
||||
target_date: `${renderDateFormat(
|
||||
calendarDateRange.startDate
|
||||
)};after,${renderDateFormat(calendarDateRange.endDate)};before`,
|
||||
group_by: null,
|
||||
}
|
||||
)
|
||||
: null
|
||||
);
|
||||
|
||||
const { data: moduleCalendarIssues } = useSWR(
|
||||
workspaceSlug && projectId && moduleId
|
||||
? MODULE_CALENDAR_ISSUES(projectId as string, moduleId as string)
|
||||
: null,
|
||||
workspaceSlug && projectId && moduleId
|
||||
? () =>
|
||||
modulesService.getModuleIssuesWithParams(
|
||||
workspaceSlug as string,
|
||||
projectId as string,
|
||||
moduleId as string,
|
||||
{
|
||||
...params,
|
||||
target_date: `${renderDateFormat(
|
||||
calendarDateRange.startDate
|
||||
)};after,${renderDateFormat(calendarDateRange.endDate)};before`,
|
||||
group_by: null,
|
||||
}
|
||||
)
|
||||
: null
|
||||
);
|
||||
const { calendarIssues, params, setCalendarDateRange } = useCalendarIssuesView();
|
||||
|
||||
const totalDate = eachDayOfInterval({
|
||||
start: calendarDateRange.startDate,
|
||||
end: calendarDateRange.endDate,
|
||||
start: calendarDates.startDate,
|
||||
end: calendarDates.endDate,
|
||||
});
|
||||
|
||||
const onlyWeekDays = weekDayInterval({
|
||||
start: calendarDateRange.startDate,
|
||||
end: calendarDateRange.endDate,
|
||||
start: calendarDates.startDate,
|
||||
end: calendarDates.endDate,
|
||||
});
|
||||
|
||||
const currentViewDays = showWeekEnds ? totalDate : onlyWeekDays;
|
||||
|
||||
const calendarIssues = cycleId
|
||||
? (cycleCalendarIssues as IIssue[])
|
||||
: moduleId
|
||||
? (moduleCalendarIssues as IIssue[])
|
||||
: (projectCalendarIssues as IIssue[]);
|
||||
|
||||
const currentViewDaysData = currentViewDays.map((date: Date) => {
|
||||
const filterIssue =
|
||||
calendarIssues && calendarIssues.length > 0
|
||||
calendarIssues.length > 0
|
||||
? calendarIssues.filter(
|
||||
(issue) =>
|
||||
issue.target_date && renderDateFormat(issue.target_date) === renderDateFormat(date)
|
||||
@ -170,13 +107,16 @@ export const CalendarView: React.FC<Props> = ({
|
||||
const { source, destination, draggableId } = result;
|
||||
|
||||
if (!destination || !workspaceSlug || !projectId) return;
|
||||
|
||||
if (source.droppableId === destination.droppableId) return;
|
||||
|
||||
const fetchKey = cycleId
|
||||
? CYCLE_CALENDAR_ISSUES(projectId as string, cycleId as string)
|
||||
? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), params)
|
||||
: moduleId
|
||||
? MODULE_CALENDAR_ISSUES(projectId as string, moduleId as string)
|
||||
: PROJECT_CALENDAR_ISSUES(projectId as string);
|
||||
? MODULE_ISSUES_WITH_PARAMS(moduleId.toString(), params)
|
||||
: viewId
|
||||
? VIEW_ISSUES(viewId.toString(), params)
|
||||
: PROJECT_ISSUES_LIST_WITH_PARAMS(projectId.toString(), params);
|
||||
|
||||
mutate<IIssue[]>(
|
||||
fetchKey,
|
||||
@ -187,16 +127,38 @@ export const CalendarView: React.FC<Props> = ({
|
||||
...p,
|
||||
target_date: destination.droppableId,
|
||||
};
|
||||
|
||||
return p;
|
||||
}),
|
||||
false
|
||||
);
|
||||
|
||||
issuesService.patchIssue(workspaceSlug as string, projectId as string, draggableId, {
|
||||
target_date: destination?.droppableId,
|
||||
});
|
||||
issuesService
|
||||
.patchIssue(workspaceSlug as string, projectId as string, draggableId, {
|
||||
target_date: destination?.droppableId,
|
||||
})
|
||||
.then(() => mutate(fetchKey));
|
||||
};
|
||||
|
||||
const changeDateRange = (startDate: Date, endDate: Date) => {
|
||||
setCalendarDates({
|
||||
startDate,
|
||||
endDate,
|
||||
});
|
||||
|
||||
setCalendarDateRange(
|
||||
`${renderDateFormat(startDate)};after,${renderDateFormat(endDate)};before`
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setCalendarDateRange(
|
||||
`${renderDateFormat(startOfWeek(currentDate))};after,${renderDateFormat(
|
||||
lastDayOfWeek(currentDate)
|
||||
)};before`
|
||||
);
|
||||
}, [currentDate]);
|
||||
|
||||
const isNotAllowed = userAuth.isGuest || userAuth.isViewer || isCompleted;
|
||||
|
||||
return calendarIssues ? (
|
||||
@ -210,7 +172,7 @@ export const CalendarView: React.FC<Props> = ({
|
||||
setShowWeekEnds={setShowWeekEnds}
|
||||
currentDate={currentDate}
|
||||
setCurrentDate={setCurrentDate}
|
||||
setCalendarDateRange={setCalendarDateRange}
|
||||
changeDateRange={changeDateRange}
|
||||
/>
|
||||
|
||||
<div
|
||||
|
@ -10,6 +10,7 @@ import { DraggableProvided, DraggableStateSnapshot } from "react-beautiful-dnd";
|
||||
// services
|
||||
import issuesService from "services/issues.service";
|
||||
// hooks
|
||||
import useCalendarIssuesView from "hooks/use-calendar-issues-view";
|
||||
import useIssuesProperties from "hooks/use-issue-properties";
|
||||
import useToast from "hooks/use-toast";
|
||||
// components
|
||||
@ -29,9 +30,10 @@ import { copyTextToClipboard, truncateText } from "helpers/string.helper";
|
||||
import { IIssue } from "types";
|
||||
// fetch-keys
|
||||
import {
|
||||
CYCLE_CALENDAR_ISSUES,
|
||||
MODULE_CALENDAR_ISSUES,
|
||||
PROJECT_CALENDAR_ISSUES,
|
||||
CYCLE_ISSUES_WITH_PARAMS,
|
||||
MODULE_ISSUES_WITH_PARAMS,
|
||||
PROJECT_ISSUES_LIST_WITH_PARAMS,
|
||||
VIEW_ISSUES,
|
||||
} from "constants/fetch-keys";
|
||||
|
||||
type Props = {
|
||||
@ -54,10 +56,12 @@ export const SingleCalendarIssue: React.FC<Props> = ({
|
||||
isNotAllowed,
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
||||
const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;
|
||||
|
||||
const { setToastAlert } = useToast();
|
||||
|
||||
const { params } = useCalendarIssuesView();
|
||||
|
||||
const [properties] = useIssuesProperties(workspaceSlug as string, projectId as string);
|
||||
|
||||
const partialUpdateIssue = useCallback(
|
||||
@ -65,20 +69,25 @@ export const SingleCalendarIssue: React.FC<Props> = ({
|
||||
if (!workspaceSlug || !projectId) return;
|
||||
|
||||
const fetchKey = cycleId
|
||||
? CYCLE_CALENDAR_ISSUES(projectId as string, cycleId as string)
|
||||
? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), params)
|
||||
: moduleId
|
||||
? MODULE_CALENDAR_ISSUES(projectId as string, moduleId as string)
|
||||
: PROJECT_CALENDAR_ISSUES(projectId as string);
|
||||
? MODULE_ISSUES_WITH_PARAMS(moduleId.toString(), params)
|
||||
: viewId
|
||||
? VIEW_ISSUES(viewId.toString(), params)
|
||||
: PROJECT_ISSUES_LIST_WITH_PARAMS(projectId.toString(), params);
|
||||
|
||||
mutate<IIssue[]>(
|
||||
fetchKey,
|
||||
(prevData) =>
|
||||
(prevData ?? []).map((p) => {
|
||||
if (p.id === issueId)
|
||||
if (p.id === issueId) {
|
||||
return {
|
||||
...p,
|
||||
formData,
|
||||
...formData,
|
||||
assignees: formData?.assignees_list ?? p.assignees,
|
||||
};
|
||||
}
|
||||
|
||||
return p;
|
||||
}),
|
||||
false
|
||||
@ -87,13 +96,13 @@ export const SingleCalendarIssue: React.FC<Props> = ({
|
||||
issuesService
|
||||
.patchIssue(workspaceSlug as string, projectId as string, issueId as string, formData)
|
||||
.then(() => {
|
||||
mutate<IIssue[]>(fetchKey);
|
||||
mutate(fetchKey);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
[workspaceSlug, projectId, cycleId, moduleId]
|
||||
[workspaceSlug, projectId, cycleId, moduleId, params]
|
||||
);
|
||||
|
||||
const handleCopyText = () => {
|
||||
@ -205,7 +214,7 @@ export const SingleCalendarIssue: React.FC<Props> = ({
|
||||
className="group flex items-center gap-1 rounded-2xl border border-brand-base px-2 py-0.5 text-xs text-brand-secondary"
|
||||
>
|
||||
<span
|
||||
className="h-1.5 w-1.5 rounded-full"
|
||||
className="h-1.5 w-1.5 rounded-full"
|
||||
style={{
|
||||
backgroundColor: label?.color && label.color !== "" ? label.color : "#000",
|
||||
}}
|
||||
|
@ -9,22 +9,21 @@ import { Dialog, Transition } from "@headlessui/react";
|
||||
// services
|
||||
import issueServices from "services/issues.service";
|
||||
// hooks
|
||||
import useToast from "hooks/use-toast";
|
||||
import useIssuesView from "hooks/use-issues-view";
|
||||
import useCalendarIssuesView from "hooks/use-calendar-issues-view";
|
||||
import useToast from "hooks/use-toast";
|
||||
// icons
|
||||
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
|
||||
// ui
|
||||
import { SecondaryButton, DangerButton } from "components/ui";
|
||||
// types
|
||||
import type { CycleIssueResponse, IIssue, ModuleIssueResponse } from "types";
|
||||
import type { IIssue } from "types";
|
||||
// fetch-keys
|
||||
import {
|
||||
CYCLE_CALENDAR_ISSUES,
|
||||
CYCLE_ISSUES_WITH_PARAMS,
|
||||
MODULE_CALENDAR_ISSUES,
|
||||
MODULE_ISSUES_WITH_PARAMS,
|
||||
PROJECT_CALENDAR_ISSUES,
|
||||
PROJECT_ISSUES_LIST_WITH_PARAMS,
|
||||
VIEW_ISSUES,
|
||||
} from "constants/fetch-keys";
|
||||
|
||||
type Props = {
|
||||
@ -37,9 +36,10 @@ export const DeleteIssueModal: React.FC<Props> = ({ isOpen, handleClose, data })
|
||||
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
||||
const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;
|
||||
|
||||
const { issueView, params } = useIssuesView();
|
||||
const { params: calendarParams } = useCalendarIssuesView();
|
||||
|
||||
const { setToastAlert } = useToast();
|
||||
|
||||
@ -61,12 +61,18 @@ export const DeleteIssueModal: React.FC<Props> = ({ isOpen, handleClose, data })
|
||||
.then(() => {
|
||||
if (issueView === "calendar") {
|
||||
const calendarFetchKey = cycleId
|
||||
? CYCLE_CALENDAR_ISSUES(projectId as string, cycleId as string)
|
||||
? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), calendarParams)
|
||||
: moduleId
|
||||
? MODULE_CALENDAR_ISSUES(projectId as string, moduleId as string)
|
||||
: PROJECT_CALENDAR_ISSUES(projectId as string);
|
||||
? MODULE_ISSUES_WITH_PARAMS(moduleId.toString(), calendarParams)
|
||||
: viewId
|
||||
? VIEW_ISSUES(viewId.toString(), calendarParams)
|
||||
: PROJECT_ISSUES_LIST_WITH_PARAMS(projectId.toString(), calendarParams);
|
||||
|
||||
mutate<IIssue[]>(calendarFetchKey);
|
||||
mutate<IIssue[]>(
|
||||
calendarFetchKey,
|
||||
(prevData) => (prevData ?? []).filter((p) => p.id !== data.id),
|
||||
false
|
||||
);
|
||||
} else {
|
||||
if (cycleId) mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params));
|
||||
else if (moduleId) mutate(MODULE_ISSUES_WITH_PARAMS(moduleId as string, params));
|
||||
|
@ -12,14 +12,14 @@ import modulesService from "services/modules.service";
|
||||
import issuesService from "services/issues.service";
|
||||
// hooks
|
||||
import useUser from "hooks/use-user";
|
||||
import useIssuesView from "hooks/use-issues-view";
|
||||
import useCalendarIssuesView from "hooks/use-calendar-issues-view";
|
||||
import useToast from "hooks/use-toast";
|
||||
// components
|
||||
import { IssueForm } from "components/issues";
|
||||
// hooks
|
||||
import useIssuesView from "hooks/use-issues-view";
|
||||
// types
|
||||
import type { IIssue } from "types";
|
||||
// fetch keys
|
||||
// fetch-keys
|
||||
import {
|
||||
PROJECT_ISSUES_DETAILS,
|
||||
PROJECT_ISSUES_LIST,
|
||||
@ -31,9 +31,7 @@ import {
|
||||
MODULE_ISSUES_WITH_PARAMS,
|
||||
CYCLE_DETAILS,
|
||||
MODULE_DETAILS,
|
||||
PROJECT_CALENDAR_ISSUES,
|
||||
CYCLE_CALENDAR_ISSUES,
|
||||
MODULE_CALENDAR_ISSUES,
|
||||
VIEW_ISSUES,
|
||||
} from "constants/fetch-keys";
|
||||
|
||||
export interface IssuesModalProps {
|
||||
@ -56,9 +54,10 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
|
||||
const [activeProject, setActiveProject] = useState<string | null>(null);
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
||||
const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;
|
||||
|
||||
const { issueView, params } = useIssuesView();
|
||||
const { params: calendarParams } = useCalendarIssuesView();
|
||||
|
||||
if (cycleId) prePopulateData = { ...prePopulateData, cycle: cycleId as string };
|
||||
if (moduleId) prePopulateData = { ...prePopulateData, module: moduleId as string };
|
||||
@ -128,23 +127,24 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
|
||||
});
|
||||
};
|
||||
|
||||
const calendarFetchKey = cycleId
|
||||
? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), calendarParams)
|
||||
: moduleId
|
||||
? MODULE_ISSUES_WITH_PARAMS(moduleId.toString(), calendarParams)
|
||||
: viewId
|
||||
? VIEW_ISSUES(viewId.toString(), calendarParams)
|
||||
: PROJECT_ISSUES_LIST_WITH_PARAMS(projectId?.toString() ?? "", calendarParams);
|
||||
|
||||
const createIssue = async (payload: Partial<IIssue>) => {
|
||||
await issuesService
|
||||
.createIssues(workspaceSlug as string, activeProject ?? "", payload)
|
||||
.then((res) => {
|
||||
mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params));
|
||||
if (issueView === "calendar") mutate(calendarFetchKey);
|
||||
|
||||
if (payload.cycle && payload.cycle !== "") addIssueToCycle(res.id, payload.cycle);
|
||||
if (payload.module && payload.module !== "") addIssueToModule(res.id, payload.module);
|
||||
|
||||
const calendarFetchKey = cycleId
|
||||
? CYCLE_CALENDAR_ISSUES(projectId as string, cycleId as string)
|
||||
: moduleId
|
||||
? MODULE_CALENDAR_ISSUES(projectId as string, moduleId as string)
|
||||
: PROJECT_CALENDAR_ISSUES(projectId as string);
|
||||
|
||||
mutate<IIssue[]>(calendarFetchKey);
|
||||
|
||||
if (!createMore) handleClose();
|
||||
|
||||
setToastAlert({
|
||||
@ -173,29 +173,8 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
|
||||
if (isUpdatingSingleIssue) {
|
||||
mutate<IIssue>(PROJECT_ISSUES_DETAILS, (prevData) => ({ ...prevData, ...res }), false);
|
||||
} else {
|
||||
if (issueView === "calendar") {
|
||||
const calendarFetchKey = cycleId
|
||||
? CYCLE_CALENDAR_ISSUES(projectId as string, cycleId as string)
|
||||
: moduleId
|
||||
? MODULE_CALENDAR_ISSUES(projectId as string, moduleId as string)
|
||||
: PROJECT_CALENDAR_ISSUES(projectId as string);
|
||||
|
||||
mutate<IIssue[]>(calendarFetchKey, (prevData) =>
|
||||
(prevData ?? []).map((i) => {
|
||||
if (i.id === res.id) return { ...i, ...res };
|
||||
return i;
|
||||
})
|
||||
);
|
||||
} else {
|
||||
mutate<IIssue[]>(
|
||||
PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params),
|
||||
(prevData) =>
|
||||
(prevData ?? []).map((i) => {
|
||||
if (i.id === res.id) return { ...i, ...res };
|
||||
return i;
|
||||
})
|
||||
);
|
||||
}
|
||||
if (issueView === "calendar") mutate(calendarFetchKey);
|
||||
else mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params));
|
||||
}
|
||||
|
||||
if (payload.cycle && payload.cycle !== "") addIssueToCycle(res.id, payload.cycle);
|
||||
|
@ -1,13 +1,14 @@
|
||||
import { IAnalyticsParams, IJiraMetadata } from "types";
|
||||
|
||||
const paramsToKey = (params: any) => {
|
||||
const { state, priority, assignees, created_by, labels } = params;
|
||||
const { state, priority, assignees, created_by, labels, target_date } = params;
|
||||
|
||||
let stateKey = state ? state.split(",") : [];
|
||||
let priorityKey = priority ? priority.split(",") : [];
|
||||
let assigneesKey = assignees ? assignees.split(",") : [];
|
||||
let createdByKey = created_by ? created_by.split(",") : [];
|
||||
let labelsKey = labels ? labels.split(",") : [];
|
||||
const targetDateKey = target_date ?? "";
|
||||
const type = params.type ? params.type.toUpperCase() : "NULL";
|
||||
const groupBy = params.group_by ? params.group_by.toUpperCase() : "NULL";
|
||||
const orderBy = params.order_by ? params.order_by.toUpperCase() : "NULL";
|
||||
@ -19,7 +20,7 @@ const paramsToKey = (params: any) => {
|
||||
createdByKey = createdByKey.sort().join("_");
|
||||
labelsKey = labelsKey.sort().join("_");
|
||||
|
||||
return `${stateKey}_${priorityKey}_${assigneesKey}_${createdByKey}_${type}_${groupBy}_${orderBy}_${labelsKey}`;
|
||||
return `${stateKey}_${priorityKey}_${assigneesKey}_${createdByKey}_${type}_${groupBy}_${orderBy}_${labelsKey}_${targetDateKey}`;
|
||||
};
|
||||
|
||||
export const CURRENT_USER = "CURRENT_USER";
|
||||
@ -148,14 +149,6 @@ export const GITHUB_REPOSITORY_INFO = (workspaceSlug: string, repoName: string)
|
||||
export const SLACK_CHANNEL_INFO = (workspaceSlug: string, projectId: string) =>
|
||||
`SLACK_CHANNEL_INFO_${workspaceSlug.toString().toUpperCase()}_${projectId.toUpperCase()}`;
|
||||
|
||||
// Calendar
|
||||
export const PROJECT_CALENDAR_ISSUES = (projectId: string) =>
|
||||
`CALENDAR_ISSUES_${projectId.toUpperCase()}`;
|
||||
export const CYCLE_CALENDAR_ISSUES = (projectId: string, cycleId: string) =>
|
||||
`CALENDAR_ISSUES_${projectId.toUpperCase()}_${cycleId.toUpperCase()}`;
|
||||
export const MODULE_CALENDAR_ISSUES = (projectId: string, moduleId: string) =>
|
||||
`CALENDAR_ISSUES_${projectId.toUpperCase()}_${moduleId.toUpperCase()}`;
|
||||
|
||||
// Pages
|
||||
export const RECENT_PAGES_LIST = (projectId: string) =>
|
||||
`RECENT_PAGES_LIST_${projectId.toUpperCase()}`;
|
||||
|
@ -34,6 +34,7 @@ type IssueViewProps = {
|
||||
groupByProperty: TIssueGroupByOptions;
|
||||
orderBy: TIssueOrderByOptions;
|
||||
showEmptyGroups: boolean;
|
||||
calendarDateRange: string;
|
||||
filters: IIssueFilterOptions;
|
||||
};
|
||||
|
||||
@ -43,6 +44,7 @@ type ReducerActionType = {
|
||||
| "SET_ISSUE_VIEW"
|
||||
| "SET_ORDER_BY_PROPERTY"
|
||||
| "SET_SHOW_EMPTY_STATES"
|
||||
| "SET_CALENDAR_DATE_RANGE"
|
||||
| "SET_FILTERS"
|
||||
| "SET_GROUP_BY_PROPERTY"
|
||||
| "RESET_TO_DEFAULT";
|
||||
@ -53,6 +55,7 @@ type ContextType = IssueViewProps & {
|
||||
setGroupByProperty: (property: TIssueGroupByOptions) => void;
|
||||
setOrderBy: (property: TIssueOrderByOptions) => void;
|
||||
setShowEmptyGroups: (property: boolean) => void;
|
||||
setCalendarDateRange: (property: string) => void;
|
||||
setFilters: (filters: Partial<IIssueFilterOptions>, saveToServer?: boolean) => void;
|
||||
resetFilterToDefault: () => void;
|
||||
setNewFilterDefaultView: () => void;
|
||||
@ -64,6 +67,7 @@ type StateType = {
|
||||
groupByProperty: TIssueGroupByOptions;
|
||||
orderBy: TIssueOrderByOptions;
|
||||
showEmptyGroups: boolean;
|
||||
calendarDateRange: string;
|
||||
filters: IIssueFilterOptions;
|
||||
};
|
||||
type ReducerFunctionType = (state: StateType, action: ReducerActionType) => StateType;
|
||||
@ -73,6 +77,7 @@ export const initialState: StateType = {
|
||||
groupByProperty: null,
|
||||
orderBy: "-created_at",
|
||||
showEmptyGroups: true,
|
||||
calendarDateRange: "",
|
||||
filters: {
|
||||
type: null,
|
||||
priority: null,
|
||||
@ -144,6 +149,18 @@ export const reducer: ReducerFunctionType = (state, action) => {
|
||||
};
|
||||
}
|
||||
|
||||
case "SET_CALENDAR_DATE_RANGE": {
|
||||
const newState = {
|
||||
...state,
|
||||
calendarDateRange: payload?.calendarDateRange || "",
|
||||
};
|
||||
|
||||
return {
|
||||
...state,
|
||||
...newState,
|
||||
};
|
||||
}
|
||||
|
||||
case "SET_FILTERS": {
|
||||
const newState = {
|
||||
...state,
|
||||
@ -410,6 +427,37 @@ export const IssueViewContextProvider: React.FC<{ children: React.ReactNode }> =
|
||||
[projectId, workspaceSlug, state, mutateMyViewProps]
|
||||
);
|
||||
|
||||
const setCalendarDateRange = useCallback(
|
||||
(value: string) => {
|
||||
dispatch({
|
||||
type: "SET_CALENDAR_DATE_RANGE",
|
||||
payload: {
|
||||
calendarDateRange: value,
|
||||
},
|
||||
});
|
||||
|
||||
if (!workspaceSlug || !projectId) return;
|
||||
|
||||
mutateMyViewProps((prevData) => {
|
||||
if (!prevData) return prevData;
|
||||
|
||||
return {
|
||||
...prevData,
|
||||
view_props: {
|
||||
...state,
|
||||
calendarDateRange: value,
|
||||
},
|
||||
};
|
||||
}, false);
|
||||
|
||||
saveDataToServer(workspaceSlug as string, projectId as string, {
|
||||
...state,
|
||||
calendarDateRange: value,
|
||||
});
|
||||
},
|
||||
[projectId, workspaceSlug, state, mutateMyViewProps]
|
||||
);
|
||||
|
||||
const setFilters = useCallback(
|
||||
(property: Partial<IIssueFilterOptions>, saveToServer = true) => {
|
||||
Object.keys(property).forEach((key) => {
|
||||
@ -577,6 +625,8 @@ export const IssueViewContextProvider: React.FC<{ children: React.ReactNode }> =
|
||||
setGroupByProperty,
|
||||
orderBy: state.orderBy,
|
||||
showEmptyGroups: state.showEmptyGroups,
|
||||
calendarDateRange: state.calendarDateRange,
|
||||
setCalendarDateRange,
|
||||
setOrderBy,
|
||||
setShowEmptyGroups,
|
||||
filters: state.filters,
|
||||
|
124
apps/app/hooks/use-calendar-issues-view.tsx
Normal file
124
apps/app/hooks/use-calendar-issues-view.tsx
Normal file
@ -0,0 +1,124 @@
|
||||
import { useContext } from "react";
|
||||
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
import useSWR from "swr";
|
||||
|
||||
// contexts
|
||||
import { issueViewContext } from "contexts/issue-view.context";
|
||||
// services
|
||||
import issuesService from "services/issues.service";
|
||||
import cyclesService from "services/cycles.service";
|
||||
import modulesService from "services/modules.service";
|
||||
// types
|
||||
import { IIssue } from "types";
|
||||
// fetch-keys
|
||||
import {
|
||||
CYCLE_ISSUES_WITH_PARAMS,
|
||||
MODULE_ISSUES_WITH_PARAMS,
|
||||
PROJECT_ISSUES_LIST_WITH_PARAMS,
|
||||
VIEW_ISSUES,
|
||||
} from "constants/fetch-keys";
|
||||
|
||||
const useCalendarIssuesView = () => {
|
||||
const {
|
||||
issueView,
|
||||
calendarDateRange,
|
||||
setCalendarDateRange,
|
||||
filters,
|
||||
setFilters,
|
||||
resetFilterToDefault,
|
||||
setNewFilterDefaultView,
|
||||
setIssueView,
|
||||
} = useContext(issueViewContext);
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;
|
||||
|
||||
const params: any = {
|
||||
assignees: filters?.assignees ? filters?.assignees.join(",") : undefined,
|
||||
state: filters?.state ? filters?.state.join(",") : undefined,
|
||||
priority: filters?.priority ? filters?.priority.join(",") : undefined,
|
||||
type: filters?.type ? filters?.type : undefined,
|
||||
labels: filters?.labels ? filters?.labels.join(",") : undefined,
|
||||
issue__assignees__id: filters?.issue__assignees__id
|
||||
? filters?.issue__assignees__id.join(",")
|
||||
: undefined,
|
||||
issue__labels__id: filters?.issue__labels__id
|
||||
? filters?.issue__labels__id.join(",")
|
||||
: undefined,
|
||||
created_by: filters?.created_by ? filters?.created_by.join(",") : undefined,
|
||||
target_date: calendarDateRange,
|
||||
};
|
||||
|
||||
const { data: projectCalendarIssues } = useSWR(
|
||||
workspaceSlug && projectId
|
||||
? PROJECT_ISSUES_LIST_WITH_PARAMS(projectId.toString(), params)
|
||||
: null,
|
||||
workspaceSlug && projectId
|
||||
? () =>
|
||||
issuesService.getIssuesWithParams(workspaceSlug.toString(), projectId.toString(), params)
|
||||
: null
|
||||
);
|
||||
|
||||
const { data: cycleCalendarIssues } = useSWR(
|
||||
workspaceSlug && projectId && cycleId
|
||||
? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), params)
|
||||
: null,
|
||||
workspaceSlug && projectId && cycleId
|
||||
? () =>
|
||||
cyclesService.getCycleIssuesWithParams(
|
||||
workspaceSlug.toString(),
|
||||
projectId.toString(),
|
||||
cycleId.toString(),
|
||||
params
|
||||
)
|
||||
: null
|
||||
);
|
||||
|
||||
const { data: moduleCalendarIssues } = useSWR(
|
||||
workspaceSlug && projectId && moduleId
|
||||
? MODULE_ISSUES_WITH_PARAMS(moduleId.toString(), params)
|
||||
: null,
|
||||
workspaceSlug && projectId && moduleId
|
||||
? () =>
|
||||
modulesService.getModuleIssuesWithParams(
|
||||
workspaceSlug.toString(),
|
||||
projectId.toString(),
|
||||
moduleId.toString(),
|
||||
params
|
||||
)
|
||||
: null
|
||||
);
|
||||
|
||||
const { data: viewCalendarIssues } = useSWR(
|
||||
workspaceSlug && projectId && viewId && params ? VIEW_ISSUES(viewId.toString(), params) : null,
|
||||
workspaceSlug && projectId && viewId && params
|
||||
? () =>
|
||||
issuesService.getIssuesWithParams(workspaceSlug.toString(), projectId.toString(), params)
|
||||
: null
|
||||
);
|
||||
|
||||
const calendarIssues = cycleId
|
||||
? (cycleCalendarIssues as IIssue[])
|
||||
: moduleId
|
||||
? (moduleCalendarIssues as IIssue[])
|
||||
: viewId
|
||||
? (viewCalendarIssues as IIssue[])
|
||||
: (projectCalendarIssues as IIssue[]);
|
||||
|
||||
return {
|
||||
issueView,
|
||||
calendarIssues: calendarIssues ?? [],
|
||||
calendarDateRange,
|
||||
setCalendarDateRange,
|
||||
filters,
|
||||
setFilters,
|
||||
params,
|
||||
resetFilterToDefault,
|
||||
setNewFilterDefaultView,
|
||||
setIssueView,
|
||||
} as const;
|
||||
};
|
||||
|
||||
export default useCalendarIssuesView;
|
@ -33,6 +33,8 @@ const useIssuesView = () => {
|
||||
setOrderBy,
|
||||
showEmptyGroups,
|
||||
setShowEmptyGroups,
|
||||
calendarDateRange,
|
||||
setCalendarDateRange,
|
||||
filters,
|
||||
setFilters,
|
||||
resetFilterToDefault,
|
||||
@ -175,6 +177,8 @@ const useIssuesView = () => {
|
||||
setOrderBy,
|
||||
showEmptyGroups,
|
||||
setShowEmptyGroups,
|
||||
calendarDateRange,
|
||||
setCalendarDateRange,
|
||||
filters,
|
||||
setFilters,
|
||||
params,
|
||||
|
1
apps/app/types/issues.d.ts
vendored
1
apps/app/types/issues.d.ts
vendored
@ -273,7 +273,6 @@ export interface IIssueViewOptions {
|
||||
group_by: TIssueGroupByOptions;
|
||||
order_by: TIssueOrderByOptions;
|
||||
filters: IIssueFilterOptions;
|
||||
target_date: string;
|
||||
}
|
||||
|
||||
export interface IIssueAttachment {
|
||||
|
1
apps/app/types/projects.d.ts
vendored
1
apps/app/types/projects.d.ts
vendored
@ -55,6 +55,7 @@ type ProjectViewTheme = {
|
||||
issueView: TIssueViewOptions;
|
||||
groupByProperty: TIssueGroupByOptions;
|
||||
orderBy: TIssueOrderByOptions;
|
||||
calendarDateRange: string;
|
||||
filters: IIssueFilterOptions;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user