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
13 changes: 1 addition & 12 deletions web/components/core/modals/bulk-delete-issues-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import issuesServices from "services/issue.service";
// hooks
import useToast from "hooks/use-toast";
import useIssuesView from "hooks/use-issues-view";
import useCalendarIssuesView from "hooks/use-calendar-issues-view";
// ui
import { DangerButton, SecondaryButton } from "components/ui";
// icons
Expand Down Expand Up @@ -55,7 +54,6 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen, user

const { setToastAlert } = useToast();
const { displayFilters, params } = useIssuesView();
const { params: calendarParams } = useCalendarIssuesView();
const { order_by, group_by, ...viewGanttParams } = params;

const {
Expand Down Expand Up @@ -90,14 +88,6 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen, user

if (!Array.isArray(data.delete_issue_ids)) data.delete_issue_ids = [data.delete_issue_ids];

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 ganttFetchKey = cycleId
? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString())
: moduleId
Expand All @@ -122,8 +112,7 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen, user
message: "Issues deleted successfully!",
});

if (displayFilters.layout === "calendar") mutate(calendarFetchKey);
else if (displayFilters.layout === "gantt_chart") mutate(ganttFetchKey);
if (displayFilters.layout === "gantt_chart") mutate(ganttFetchKey);
else {
if (cycleId) {
mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), params));
Expand Down
2 changes: 0 additions & 2 deletions web/components/core/views/calendar-view/calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import { mutate } from "swr";
import { DragDropContext, DropResult } from "react-beautiful-dnd";
// services
import issuesService from "services/issue.service";
// hooks
import useCalendarIssuesView from "hooks/use-calendar-issues-view";
// components
import { SingleCalendarDate, CalendarHeader } from "components/core";
import { IssuePeekOverview } from "components/issues";
Expand Down
3 changes: 1 addition & 2 deletions web/components/core/views/calendar-view/single-issue.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { DraggableProvided, DraggableStateSnapshot } from "react-beautiful-dnd";
import issuesService from "services/issue.service";
import trackEventServices from "services/track_event.service";
// hooks
import useCalendarIssuesView from "hooks/use-calendar-issues-view";
import useIssuesProperties from "hooks/use-issue-properties";
import useToast from "hooks/use-toast";
// components
Expand Down Expand Up @@ -60,7 +59,7 @@ export const SingleCalendarIssue: React.FC<Props> = ({

const { setToastAlert } = useToast();

const { params } = useCalendarIssuesView();
const params = {};

const [properties] = useIssuesProperties(workspaceSlug as string, projectId as string);

Expand Down
1 change: 1 addition & 0 deletions web/components/headers/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./module-issues";
export * from "./project-issues";
94 changes: 94 additions & 0 deletions web/components/headers/module-issues.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { useCallback } from "react";
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";

// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// components
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues";
// types
import { IIssueDisplayFilterOptions, IIssueFilterOptions, TIssueLayouts } from "types";
// constants
import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";

export const ModuleIssuesHeader: React.FC = observer(() => {
const router = useRouter();
const { workspaceSlug, projectId, moduleId } = router.query;

const { issueFilter: issueFilterStore, moduleFilter: moduleFilterStore } = useMobxStore();

const activeLayout = issueFilterStore.userDisplayFilters.layout;

const handleLayoutChange = useCallback(
(layout: TIssueLayouts) => {
if (!workspaceSlug || !projectId) return;

issueFilterStore.updateUserFilters(workspaceSlug.toString(), projectId.toString(), {
display_filters: {
layout,
},
});
},
[issueFilterStore, projectId, workspaceSlug]
);

const handleFiltersUpdate = useCallback(
(key: keyof IIssueFilterOptions, value: string | string[]) => {
if (!workspaceSlug || !projectId || !moduleId) return;

const newValues = moduleFilterStore.userModuleFilters?.[key] ?? [];

if (Array.isArray(value)) {
value.forEach((val) => {
if (!newValues.includes(val)) newValues.push(val);
});
} else {
if (moduleFilterStore.userModuleFilters?.[key]?.includes(value)) newValues.splice(newValues.indexOf(value), 1);
else newValues.push(value);
}

moduleFilterStore.updateUserModuleFilters(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), {
[key]: newValues,
});
},
[moduleId, moduleFilterStore, projectId, workspaceSlug]
);

const handleDisplayFiltersUpdate = useCallback(
(updatedDisplayFilter: Partial<IIssueDisplayFilterOptions>) => {
if (!workspaceSlug || !projectId) return;

issueFilterStore.updateUserFilters(workspaceSlug.toString(), projectId.toString(), {
display_filters: {
...updatedDisplayFilter,
},
});
},
[issueFilterStore, projectId, workspaceSlug]
);

return (
<div className="flex items-center gap-2">
<LayoutSelection
layouts={["list", "kanban", "calendar", "spreadsheet", "gantt_chart"]}
onChange={(layout) => handleLayoutChange(layout)}
selectedLayout={activeLayout}
/>
<FiltersDropdown title="Filters">
<FilterSelection
filters={moduleFilterStore.userModuleFilters}
handleFiltersUpdate={handleFiltersUpdate}
layoutDisplayFiltersOptions={activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined}
projectId={projectId?.toString() ?? ""}
/>
</FiltersDropdown>
<FiltersDropdown title="View">
<DisplayFiltersSelection
displayFilters={issueFilterStore.userDisplayFilters}
handleDisplayFiltersUpdate={handleDisplayFiltersUpdate}
layoutDisplayFiltersOptions={activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined}
/>
</FiltersDropdown>
</div>
);
});
14 changes: 1 addition & 13 deletions web/components/issues/delete-issue-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { Dialog, Transition } from "@headlessui/react";
import issueServices from "services/issue.service";
// hooks
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";
Expand Down Expand Up @@ -52,7 +51,6 @@ export const DeleteIssueModal: React.FC<Props> = ({
const isArchivedIssues = router.pathname.includes("archived-issues");

const { displayFilters, params } = useIssuesView();
const { params: calendarParams } = useCalendarIssuesView();

const { setToastAlert } = useToast();

Expand All @@ -73,17 +71,7 @@ export const DeleteIssueModal: React.FC<Props> = ({
await issueServices
.deleteIssue(workspaceSlug as string, data.project, data.id, user)
.then(() => {
if (displayFilters.layout === "calendar") {
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(data.project, calendarParams);

mutate<IIssue[]>(calendarFetchKey, (prevData) => (prevData ?? []).filter((p) => p.id !== data.id), false);
} else if (displayFilters.layout === "spreadsheet") {
if (displayFilters.layout === "spreadsheet") {
if (data.parent) {
mutate<ISubIssueResponse>(
SUB_ISSUES(data.parent.toString()),
Expand Down
13 changes: 0 additions & 13 deletions web/components/issues/draft-issue-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import issuesService from "services/issue.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";
import useLocalStorage from "hooks/use-local-storage";
import useProjects from "hooks/use-projects";
Expand Down Expand Up @@ -78,7 +77,6 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = (props) =
const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;

const { displayFilters, params } = useIssuesView();
const { params: calendarParams } = useCalendarIssuesView();
const { ...viewGanttParams } = params;

const { user } = useUser();
Expand Down Expand Up @@ -146,14 +144,6 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = (props) =
setActiveProject(projects?.find((p) => p.id === projectId)?.id ?? projects?.[0].id ?? null);
}, [activeProject, data, projectId, projects, isOpen, prePopulateData]);

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(activeProject?.toString() ?? "", calendarParams);

const ganttFetchKey = cycleId
? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString())
: moduleId
Expand All @@ -171,7 +161,6 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = (props) =
mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params));
mutate(PROJECT_DRAFT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params));

if (displayFilters.layout === "calendar") mutate(calendarFetchKey);
if (displayFilters.layout === "gantt_chart")
mutate(ganttFetchKey, {
start_target_date: true,
Expand Down Expand Up @@ -210,7 +199,6 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = (props) =
if (isUpdatingSingleIssue) {
mutate<IIssue>(PROJECT_ISSUES_DETAILS, (prevData) => ({ ...prevData, ...res }), false);
} else {
if (displayFilters.layout === "calendar") mutate(calendarFetchKey);
if (payload.parent) mutate(SUB_ISSUES(payload.parent.toString()));
mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params));
mutate(PROJECT_DRAFT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params));
Expand Down Expand Up @@ -290,7 +278,6 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = (props) =
if (payload.cycle && payload.cycle !== "") await addIssueToCycle(res.id, payload.cycle);
if (payload.module && payload.module !== "") await addIssueToModule(res.id, payload.module);

if (displayFilters.layout === "calendar") mutate(calendarFetchKey);
if (displayFilters.layout === "gantt_chart")
mutate(ganttFetchKey, {
start_target_date: true,
Expand Down
1 change: 1 addition & 0 deletions web/components/issues/issue-layouts/calendar/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from "./types.d";
export * from "./day-tile";
export * from "./header";
export * from "./issue-blocks";
export * from "./module-root";
export * from "./root";
export * from "./week-days";
export * from "./week-header";
36 changes: 36 additions & 0 deletions web/components/issues/issue-layouts/calendar/module-root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { observer } from "mobx-react-lite";
import { DragDropContext, DropResult } from "@hello-pangea/dnd";

// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// components
import { CalendarChart } from "components/issues";
// types
import { IIssueGroupedStructure } from "store/issue";

export const ModuleCalendarLayout: React.FC = observer(() => {
const { module: moduleStore } = useMobxStore();

// TODO: add drag and drop functionality
const onDragEnd = (result: DropResult) => {
if (!result) return;

// return if not dropped on the correct place
if (!result.destination) return;

// return if dropped on the same date
if (result.destination.droppableId === result.source.droppableId) return;

// issueKanBanViewStore?.handleDragDrop(result.source, result.destination);
};

const issues = moduleStore.getIssues;

return (
<div className="h-full w-full pt-4 bg-custom-background-100 overflow-hidden">
<DragDropContext onDragEnd={onDragEnd}>
<CalendarChart issues={issues as IIssueGroupedStructure | null} />
</DragDropContext>
</div>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from "./date";
export * from "./filters-list";
export * from "./label";
export * from "./members";
export * from "./module-root";
export * from "./priority";
export * from "./root";
export * from "./state";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";

// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// components
import { AppliedFiltersList } from "components/issues";
// types
import { IIssueFilterOptions } from "types";

export const ModuleAppliedFiltersRoot: React.FC = observer(() => {
const router = useRouter();
const { workspaceSlug, projectId, moduleId } = router.query;

const { project: projectStore, moduleFilter: moduleFilterStore } = useMobxStore();

const userFilters = moduleFilterStore.userModuleFilters;

// filters whose value not null or empty array
const appliedFilters: IIssueFilterOptions = {};
Object.entries(userFilters).forEach(([key, value]) => {
if (!value) return;

if (Array.isArray(value) && value.length === 0) return;

appliedFilters[key as keyof IIssueFilterOptions] = value;
});

const handleRemoveFilter = (key: keyof IIssueFilterOptions, value: string | null) => {
if (!workspaceSlug || !projectId || !moduleId) return;

// remove all values of the key if value is null
if (!value) {
moduleFilterStore.updateUserModuleFilters(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), {
[key]: null,
});
return;
}

// remove the passed value from the key
let newValues = moduleFilterStore.userModuleFilters?.[key] ?? [];
newValues = newValues.filter((val) => val !== value);

moduleFilterStore.updateUserModuleFilters(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), {
[key]: newValues,
});
};

const handleClearAllFilters = () => {
if (!workspaceSlug || !projectId || !moduleId) return;

const newFilters: IIssueFilterOptions = {};
Object.keys(userFilters).forEach((key) => {
newFilters[key as keyof IIssueFilterOptions] = null;
});

moduleFilterStore.updateUserModuleFilters(workspaceSlug.toString(), projectId.toString(), moduleId?.toString(), {
...newFilters,
});
};

// return if no filters are applied
if (Object.keys(appliedFilters).length === 0) return null;

return (
<AppliedFiltersList
appliedFilters={appliedFilters}
handleClearAllFilters={handleClearAllFilters}
handleRemoveFilter={handleRemoveFilter}
labels={projectStore.labels?.[projectId?.toString() ?? ""] ?? []}
members={projectStore.members?.[projectId?.toString() ?? ""]?.map((m) => m.member)}
states={projectStore.states?.[projectId?.toString() ?? ""]}
/>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const AppliedFiltersRoot: React.FC = observer(() => {
const router = useRouter();
const { workspaceSlug, projectId } = router.query;

const { issueFilter: issueFilterStore, project: projectStore } = useMobxStore();
const { issueFilter: issueFilterStore, project: projectStore, moduleFilter: moduleFilterStore } = useMobxStore();

const userFilters = issueFilterStore.userFilters;

Expand Down
1 change: 1 addition & 0 deletions web/components/issues/issue-layouts/gantt/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./blocks";
export * from "./module-root";
export * from "./root";
Loading