mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
feat: calendar filters (#908)
* feat: hiding unnecessary filters for calendar view * feat: filters for calendar view * feat: module and cycle calendar view filters
This commit is contained in:
parent
2ba4594b29
commit
9129a6cde2
@ -26,7 +26,7 @@ import {
|
|||||||
import { Popover, Transition } from "@headlessui/react";
|
import { Popover, Transition } from "@headlessui/react";
|
||||||
import { DragDropContext, Draggable, DropResult } from "react-beautiful-dnd";
|
import { DragDropContext, Draggable, DropResult } from "react-beautiful-dnd";
|
||||||
import StrictModeDroppable from "components/dnd/StrictModeDroppable";
|
import StrictModeDroppable from "components/dnd/StrictModeDroppable";
|
||||||
import { CustomMenu } from "components/ui";
|
import { CustomMenu, Spinner } from "components/ui";
|
||||||
// icon
|
// icon
|
||||||
import {
|
import {
|
||||||
CheckIcon,
|
CheckIcon,
|
||||||
@ -35,6 +35,8 @@ import {
|
|||||||
ChevronRightIcon,
|
ChevronRightIcon,
|
||||||
PlusIcon,
|
PlusIcon,
|
||||||
} from "@heroicons/react/24/outline";
|
} from "@heroicons/react/24/outline";
|
||||||
|
// hooks
|
||||||
|
import useIssuesView from "hooks/use-issues-view";
|
||||||
// services
|
// services
|
||||||
import issuesService from "services/issues.service";
|
import issuesService from "services/issues.service";
|
||||||
import cyclesService from "services/cycles.service";
|
import cyclesService from "services/cycles.service";
|
||||||
@ -67,6 +69,8 @@ export const CalendarView: React.FC<Props> = ({ addIssueToDate }) => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
||||||
|
|
||||||
|
const { params } = useIssuesView();
|
||||||
|
|
||||||
const [calendarDateRange, setCalendarDateRange] = useState<ICalendarRange>({
|
const [calendarDateRange, setCalendarDateRange] = useState<ICalendarRange>({
|
||||||
startDate: startOfWeek(currentDate),
|
startDate: startOfWeek(currentDate),
|
||||||
endDate: lastDayOfWeek(currentDate),
|
endDate: lastDayOfWeek(currentDate),
|
||||||
@ -82,11 +86,13 @@ export const CalendarView: React.FC<Props> = ({ addIssueToDate }) => {
|
|||||||
workspaceSlug && projectId ? PROJECT_CALENDAR_ISSUES(projectId as string) : null,
|
workspaceSlug && projectId ? PROJECT_CALENDAR_ISSUES(projectId as string) : null,
|
||||||
workspaceSlug && projectId
|
workspaceSlug && projectId
|
||||||
? () =>
|
? () =>
|
||||||
issuesService.getIssuesWithParams(
|
issuesService.getIssuesWithParams(workspaceSlug as string, projectId as string, {
|
||||||
workspaceSlug as string,
|
...params,
|
||||||
projectId as string,
|
target_date: `${renderDateFormat(calendarDateRange.startDate)};after,${renderDateFormat(
|
||||||
targetDateFilter
|
calendarDateRange.endDate
|
||||||
)
|
)};before`,
|
||||||
|
group_by: null,
|
||||||
|
})
|
||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -100,7 +106,13 @@ export const CalendarView: React.FC<Props> = ({ addIssueToDate }) => {
|
|||||||
workspaceSlug as string,
|
workspaceSlug as string,
|
||||||
projectId as string,
|
projectId as string,
|
||||||
cycleId as string,
|
cycleId as string,
|
||||||
targetDateFilter
|
{
|
||||||
|
...params,
|
||||||
|
target_date: `${renderDateFormat(calendarDateRange.startDate)};after,${renderDateFormat(
|
||||||
|
calendarDateRange.endDate
|
||||||
|
)};before`,
|
||||||
|
group_by: null,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
@ -115,7 +127,13 @@ export const CalendarView: React.FC<Props> = ({ addIssueToDate }) => {
|
|||||||
workspaceSlug as string,
|
workspaceSlug as string,
|
||||||
projectId as string,
|
projectId as string,
|
||||||
moduleId as string,
|
moduleId as string,
|
||||||
targetDateFilter
|
{
|
||||||
|
...params,
|
||||||
|
target_date: `${renderDateFormat(calendarDateRange.startDate)};after,${renderDateFormat(
|
||||||
|
calendarDateRange.endDate
|
||||||
|
)};before`,
|
||||||
|
group_by: null,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
@ -132,7 +150,11 @@ export const CalendarView: React.FC<Props> = ({ addIssueToDate }) => {
|
|||||||
|
|
||||||
const currentViewDays = showWeekEnds ? totalDate : onlyWeekDays;
|
const currentViewDays = showWeekEnds ? totalDate : onlyWeekDays;
|
||||||
|
|
||||||
const calendarIssues = cycleCalendarIssues ?? moduleCalendarIssues ?? projectCalendarIssues;
|
const calendarIssues = cycleId
|
||||||
|
? cycleCalendarIssues
|
||||||
|
: moduleId
|
||||||
|
? moduleCalendarIssues
|
||||||
|
: projectCalendarIssues;
|
||||||
|
|
||||||
const currentViewDaysData = currentViewDays.map((date: Date) => {
|
const currentViewDaysData = currentViewDays.map((date: Date) => {
|
||||||
const filterIssue =
|
const filterIssue =
|
||||||
@ -203,11 +225,11 @@ export const CalendarView: React.FC<Props> = ({ addIssueToDate }) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return calendarIssues ? (
|
||||||
<DragDropContext onDragEnd={onDragEnd}>
|
<DragDropContext onDragEnd={onDragEnd}>
|
||||||
<div className="h-full overflow-y-auto rounded-lg text-gray-600 -m-2">
|
<div className="-m-2 h-full overflow-y-auto rounded-lg text-gray-600">
|
||||||
<div className="mb-4 flex items-center justify-between">
|
<div className="mb-4 flex items-center justify-between">
|
||||||
<div className="relative flex h-full w-full gap-2 items-center justify-start text-sm ">
|
<div className="relative flex h-full w-full items-center justify-start gap-2 text-sm ">
|
||||||
<Popover className="flex h-full items-center justify-start rounded-lg">
|
<Popover className="flex h-full items-center justify-start rounded-lg">
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
<>
|
<>
|
||||||
@ -227,8 +249,8 @@ export const CalendarView: React.FC<Props> = ({ addIssueToDate }) => {
|
|||||||
leaveFrom="opacity-100 translate-y-0"
|
leaveFrom="opacity-100 translate-y-0"
|
||||||
leaveTo="opacity-0 translate-y-1"
|
leaveTo="opacity-0 translate-y-1"
|
||||||
>
|
>
|
||||||
<Popover.Panel className="absolute top-10 left-0 z-20 w-full max-w-xs flex flex-col transform overflow-hidden bg-brand-surface-2 shadow-lg rounded-[10px]">
|
<Popover.Panel className="absolute top-10 left-0 z-20 flex w-full max-w-xs transform flex-col overflow-hidden rounded-[10px] bg-brand-surface-2 shadow-lg">
|
||||||
<div className="flex justify-center items-center text-sm gap-5 px-2 py-2">
|
<div className="flex items-center justify-center gap-5 px-2 py-2 text-sm">
|
||||||
{yearOptions.map((year) => (
|
{yearOptions.map((year) => (
|
||||||
<button
|
<button
|
||||||
onClick={() => updateDate(updateDateWithYear(year.label, currentDate))}
|
onClick={() => updateDate(updateDateWithYear(year.label, currentDate))}
|
||||||
@ -236,19 +258,19 @@ export const CalendarView: React.FC<Props> = ({ addIssueToDate }) => {
|
|||||||
isSameYear(year.value, currentDate)
|
isSameYear(year.value, currentDate)
|
||||||
? "text-sm font-medium text-gray-800"
|
? "text-sm font-medium text-gray-800"
|
||||||
: "text-xs text-gray-400 "
|
: "text-xs text-gray-400 "
|
||||||
} hover:text-sm hover:text-gray-800 hover:font-medium`}
|
} hover:text-sm hover:font-medium hover:text-gray-800`}
|
||||||
>
|
>
|
||||||
{year.label}
|
{year.label}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-4 px-2 border-t border-brand-base">
|
<div className="grid grid-cols-4 border-t border-brand-base px-2">
|
||||||
{monthOptions.map((month) => (
|
{monthOptions.map((month) => (
|
||||||
<button
|
<button
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
updateDate(updateDateWithMonth(month.value, currentDate))
|
updateDate(updateDateWithMonth(month.value, currentDate))
|
||||||
}
|
}
|
||||||
className={`text-gray-400 text-xs px-2 py-2 hover:font-medium hover:text-gray-800 ${
|
className={`px-2 py-2 text-xs text-gray-400 hover:font-medium hover:text-gray-800 ${
|
||||||
isSameMonth(month.value, currentDate)
|
isSameMonth(month.value, currentDate)
|
||||||
? "font-medium text-gray-800"
|
? "font-medium text-gray-800"
|
||||||
: ""
|
: ""
|
||||||
@ -300,7 +322,7 @@ export const CalendarView: React.FC<Props> = ({ addIssueToDate }) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex w-full gap-2 items-center justify-end">
|
<div className="flex w-full items-center justify-end gap-2">
|
||||||
<button
|
<button
|
||||||
className="group flex cursor-pointer items-center gap-2 rounded-md border border-brand-base bg-brand-surface-2 px-4 py-1.5 text-sm hover:bg-brand-surface-1 hover:text-brand-base focus:outline-none"
|
className="group flex cursor-pointer items-center gap-2 rounded-md border border-brand-base bg-brand-surface-2 px-4 py-1.5 text-sm hover:bg-brand-surface-1 hover:text-brand-base focus:outline-none"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -317,6 +339,7 @@ export const CalendarView: React.FC<Props> = ({ addIssueToDate }) => {
|
|||||||
>
|
>
|
||||||
Today{" "}
|
Today{" "}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<CustomMenu
|
<CustomMenu
|
||||||
customButton={
|
customButton={
|
||||||
<div
|
<div
|
||||||
@ -397,7 +420,7 @@ export const CalendarView: React.FC<Props> = ({ addIssueToDate }) => {
|
|||||||
{weeks.map((date, index) => (
|
{weeks.map((date, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className={`flex items-center justify-start p-1.5 gap-2 border-brand-base bg-brand-surface-1 text-base font-medium text-gray-600 ${
|
className={`flex items-center justify-start gap-2 border-brand-base bg-brand-surface-1 p-1.5 text-base font-medium text-gray-600 ${
|
||||||
!isMonthlyView
|
!isMonthlyView
|
||||||
? showWeekEnds
|
? showWeekEnds
|
||||||
? (index + 1) % 7 === 0
|
? (index + 1) % 7 === 0
|
||||||
@ -480,5 +503,9 @@ export const CalendarView: React.FC<Props> = ({ addIssueToDate }) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</DragDropContext>
|
</DragDropContext>
|
||||||
|
) : (
|
||||||
|
<div className="flex h-full w-full items-center justify-center">
|
||||||
|
<Spinner />
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -137,12 +137,14 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
<Popover.Panel className="absolute right-0 z-20 mt-1 w-screen max-w-xs transform overflow-hidden rounded-lg bg-brand-surface-2 p-3 shadow-lg">
|
<Popover.Panel className="absolute right-0 z-20 mt-1 w-screen max-w-xs transform overflow-hidden rounded-lg bg-brand-surface-2 p-3 shadow-lg">
|
||||||
<div className="relative divide-y-2 divide-brand-base">
|
<div className="relative divide-y-2 divide-brand-base">
|
||||||
<div className="space-y-4 pb-3 text-xs">
|
<div className="space-y-4 pb-3 text-xs">
|
||||||
|
{issueView !== "calendar" && (
|
||||||
|
<>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h4 className="text-brand-secondary">Group by</h4>
|
<h4 className="text-brand-secondary">Group by</h4>
|
||||||
<CustomMenu
|
<CustomMenu
|
||||||
label={
|
label={
|
||||||
GROUP_BY_OPTIONS.find((option) => option.key === groupByProperty)?.name ??
|
GROUP_BY_OPTIONS.find((option) => option.key === groupByProperty)
|
||||||
"Select"
|
?.name ?? "Select"
|
||||||
}
|
}
|
||||||
width="lg"
|
width="lg"
|
||||||
>
|
>
|
||||||
@ -181,6 +183,8 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
)}
|
)}
|
||||||
</CustomMenu>
|
</CustomMenu>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h4 className="text-brand-secondary">Issue type</h4>
|
<h4 className="text-brand-secondary">Issue type</h4>
|
||||||
<CustomMenu
|
<CustomMenu
|
||||||
@ -204,6 +208,9 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
))}
|
))}
|
||||||
</CustomMenu>
|
</CustomMenu>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{issueView !== "calendar" && (
|
||||||
|
<>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h4 className="text-brand-secondary">Show empty states</h4>
|
<h4 className="text-brand-secondary">Show empty states</h4>
|
||||||
<button
|
<button
|
||||||
@ -236,7 +243,10 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
Set as default
|
Set as default
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
{issueView !== "calendar" && (
|
||||||
<div className="space-y-2 py-3">
|
<div className="space-y-2 py-3">
|
||||||
<h4 className="text-sm text-brand-secondary">Display Properties</h4>
|
<h4 className="text-sm text-brand-secondary">Display Properties</h4>
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
@ -260,6 +270,7 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Popover.Panel>
|
</Popover.Panel>
|
||||||
</Transition>
|
</Transition>
|
||||||
|
@ -396,7 +396,6 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
handleClose={() => setTransferIssuesModal(false)}
|
handleClose={() => setTransferIssuesModal(false)}
|
||||||
isOpen={transferIssuesModal}
|
isOpen={transferIssuesModal}
|
||||||
/>
|
/>
|
||||||
{issueView !== "calendar" && (
|
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
className={`flex items-center justify-between gap-2 ${
|
className={`flex items-center justify-between gap-2 ${
|
||||||
@ -430,7 +429,7 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
<div className={` ${issueView === "list" ? "mt-4" : "my-4"} border-t`} />
|
<div className={` ${issueView === "list" ? "mt-4" : "my-4"} border-t`} />
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
|
||||||
<DragDropContext onDragEnd={handleOnDragEnd}>
|
<DragDropContext onDragEnd={handleOnDragEnd}>
|
||||||
<StrictModeDroppable droppableId="trashBox">
|
<StrictModeDroppable droppableId="trashBox">
|
||||||
{(provided, snapshot) => (
|
{(provided, snapshot) => (
|
||||||
|
@ -297,6 +297,14 @@ export const IssueViewContextProvider: React.FC<{ children: React.ReactNode }> =
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (property === "calendar") {
|
||||||
|
dispatch({
|
||||||
|
type: "SET_GROUP_BY_PROPERTY",
|
||||||
|
payload: {
|
||||||
|
groupByProperty: null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user