forked from github/plane
chore: implemented drag and drop between dates for project issues, cycle, module, and project views for calendar layout (#2535)
This commit is contained in:
parent
cea39c758e
commit
a6d741e784
@ -29,35 +29,46 @@ export const CalendarDayTile: React.FC<Props> = observer((props) => {
|
||||
const issuesList = issues ? (issues as IIssueGroupedStructure)[renderDateFormat(date.date)] : null;
|
||||
|
||||
return (
|
||||
<Droppable droppableId={renderDateFormat(date.date)}>
|
||||
{(provided, snapshot) => (
|
||||
<>
|
||||
<div className="w-full h-full relative flex flex-col bg-custom-background-90">
|
||||
{/* header */}
|
||||
<div
|
||||
className={`flex-grow p-2 space-y-1 w-full flex flex-col overflow-hidden ${
|
||||
snapshot.isDraggingOver || date.date.getDay() === 0 || date.date.getDay() === 6
|
||||
className={`text-xs text-right flex-shrink-0 py-1 px-2 ${
|
||||
calendarLayout === "month" // if month layout, highlight current month days
|
||||
? date.is_current_month
|
||||
? "font-medium"
|
||||
: "text-custom-text-300"
|
||||
: "font-medium" // if week layout, highlight all days
|
||||
} ${
|
||||
date.date.getDay() === 0 || date.date.getDay() === 6
|
||||
? "bg-custom-background-90"
|
||||
: "bg-custom-background-100"
|
||||
} ${calendarLayout === "month" ? "min-h-[9rem]" : ""}`}
|
||||
{...provided.droppableProps}
|
||||
ref={provided.innerRef}
|
||||
}`}
|
||||
>
|
||||
<>
|
||||
<div
|
||||
className={`text-xs text-right ${
|
||||
calendarLayout === "month" // if month layout, highlight current month days
|
||||
? date.is_current_month
|
||||
? "font-medium"
|
||||
: "text-custom-text-300"
|
||||
: "font-medium" // if week layout, highlight all days
|
||||
}`}
|
||||
>
|
||||
{date.date.getDate() === 1 && MONTHS_LIST[date.date.getMonth() + 1].shortTitle + " "}
|
||||
{date.date.getDate()}
|
||||
</div>
|
||||
<CalendarIssueBlocks issues={issuesList} quickActions={quickActions} />
|
||||
{provided.placeholder}
|
||||
</>
|
||||
{date.date.getDate() === 1 && MONTHS_LIST[date.date.getMonth() + 1].shortTitle + " "}
|
||||
{date.date.getDate()}
|
||||
</div>
|
||||
)}
|
||||
</Droppable>
|
||||
|
||||
{/* content */}
|
||||
<div className="w-full h-full">
|
||||
<Droppable droppableId={renderDateFormat(date.date)} isDropDisabled={false}>
|
||||
{(provided, snapshot) => (
|
||||
<div
|
||||
className={`h-full w-full overflow-y-auto select-none ${
|
||||
snapshot.isDraggingOver || date.date.getDay() === 0 || date.date.getDay() === 6
|
||||
? "bg-custom-background-90"
|
||||
: "bg-custom-background-100"
|
||||
} ${calendarLayout === "month" ? "min-h-[9rem]" : ""}`}
|
||||
{...provided.droppableProps}
|
||||
ref={provided.innerRef}
|
||||
>
|
||||
<CalendarIssueBlocks issues={issuesList} quickActions={quickActions} />
|
||||
{provided.placeholder}
|
||||
</div>
|
||||
)}
|
||||
</Droppable>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
@ -17,42 +17,46 @@ export const CalendarIssueBlocks: React.FC<Props> = observer((props) => {
|
||||
const { workspaceSlug } = router.query;
|
||||
|
||||
return (
|
||||
<div className="space-y-2 h-full w-full overflow-y-auto p-0.5">
|
||||
<>
|
||||
{issues?.map((issue, index) => (
|
||||
<Draggable key={issue.id} draggableId={issue.id} index={index}>
|
||||
{(provided, snapshot) => (
|
||||
<Link href={`/${workspaceSlug?.toString()}/projects/${issue.project}/issues/${issue.id}`}>
|
||||
<a
|
||||
className={`group/calendar-block h-8 w-full shadow-custom-shadow-2xs rounded py-1.5 px-1 flex items-center gap-1.5 border-[0.5px] border-custom-border-100 ${
|
||||
snapshot.isDragging
|
||||
? "shadow-custom-shadow-rg bg-custom-background-90"
|
||||
: "bg-custom-background-100 hover:bg-custom-background-90"
|
||||
}`}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
ref={provided.innerRef}
|
||||
>
|
||||
<span
|
||||
className="h-full w-0.5 rounded flex-shrink-0"
|
||||
style={{
|
||||
backgroundColor: issue.state_detail.color,
|
||||
}}
|
||||
/>
|
||||
<div className="text-xs text-custom-text-300 flex-shrink-0">
|
||||
{issue.project_detail.identifier}-{issue.sequence_id}
|
||||
</div>
|
||||
<h6 className="text-xs flex-grow truncate">{issue.name}</h6>
|
||||
<div className="hidden group-hover/calendar-block:block">{quickActions(issue)}</div>
|
||||
{/* <IssueQuickActions
|
||||
<div
|
||||
className="p-1 px-2"
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
ref={provided.innerRef}
|
||||
>
|
||||
<Link href={`/${workspaceSlug?.toString()}/projects/${issue.project}/issues/${issue.id}`}>
|
||||
<a
|
||||
className={`group/calendar-block h-8 w-full shadow-custom-shadow-2xs rounded py-1.5 px-1 flex items-center gap-1.5 border-[0.5px] border-custom-border-100 ${
|
||||
snapshot.isDragging
|
||||
? "shadow-custom-shadow-rg bg-custom-background-90"
|
||||
: "bg-custom-background-100 hover:bg-custom-background-90"
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
className="h-full w-0.5 rounded flex-shrink-0"
|
||||
style={{
|
||||
backgroundColor: issue.state_detail.color,
|
||||
}}
|
||||
/>
|
||||
<div className="text-xs text-custom-text-300 flex-shrink-0">
|
||||
{issue.project_detail.identifier}-{issue.sequence_id}
|
||||
</div>
|
||||
<h6 className="text-xs flex-grow truncate">{issue.name}</h6>
|
||||
<div className="hidden group-hover/calendar-block:block">{quickActions(issue)}</div>
|
||||
{/* <IssueQuickActions
|
||||
issue={issue}
|
||||
handleDelete={async () => handleIssues(issue.target_date ?? "", issue, "delete")}
|
||||
handleUpdate={async (data) => handleIssues(issue.target_date ?? "", data, "update")}
|
||||
/> */}
|
||||
</a>
|
||||
</Link>
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
@ -11,12 +11,16 @@ import { IIssueGroupedStructure } from "store/issue";
|
||||
import { IIssue } from "types";
|
||||
|
||||
export const CycleCalendarLayout: React.FC = observer(() => {
|
||||
const { cycleIssue: cycleIssueStore, issueFilter: issueFilterStore, issueDetail: issueDetailStore } = useMobxStore();
|
||||
const {
|
||||
cycleIssue: cycleIssueStore,
|
||||
issueFilter: issueFilterStore,
|
||||
issueDetail: issueDetailStore,
|
||||
cycleIssueCalendarView: cycleIssueCalendarViewStore,
|
||||
} = useMobxStore();
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, cycleId } = router.query;
|
||||
|
||||
// TODO: add drag and drop functionality
|
||||
const onDragEnd = (result: DropResult) => {
|
||||
if (!result) return;
|
||||
|
||||
@ -26,7 +30,7 @@ export const CycleCalendarLayout: React.FC = observer(() => {
|
||||
// return if dropped on the same date
|
||||
if (result.destination.droppableId === result.source.droppableId) return;
|
||||
|
||||
// issueKanBanViewStore?.handleDragDrop(result.source, result.destination);
|
||||
cycleIssueCalendarViewStore?.handleDragDrop(result.source, result.destination);
|
||||
};
|
||||
|
||||
const issues = cycleIssueStore.getIssues;
|
||||
|
@ -15,12 +15,12 @@ export const ModuleCalendarLayout: React.FC = observer(() => {
|
||||
moduleIssue: moduleIssueStore,
|
||||
issueFilter: issueFilterStore,
|
||||
issueDetail: issueDetailStore,
|
||||
moduleIssueCalendarView: moduleIssueCalendarViewStore,
|
||||
} = useMobxStore();
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, moduleId } = router.query;
|
||||
|
||||
// TODO: add drag and drop functionality
|
||||
const onDragEnd = (result: DropResult) => {
|
||||
if (!result) return;
|
||||
|
||||
@ -30,7 +30,7 @@ export const ModuleCalendarLayout: React.FC = observer(() => {
|
||||
// return if dropped on the same date
|
||||
if (result.destination.droppableId === result.source.droppableId) return;
|
||||
|
||||
// issueKanBanViewStore?.handleDragDrop(result.source, result.destination);
|
||||
moduleIssueCalendarViewStore?.handleDragDrop(result.source, result.destination);
|
||||
};
|
||||
|
||||
const issues = moduleIssueStore.getIssues;
|
||||
|
@ -11,12 +11,16 @@ import { IIssueGroupedStructure } from "store/issue";
|
||||
import { IIssue } from "types";
|
||||
|
||||
export const CalendarLayout: React.FC = observer(() => {
|
||||
const { issue: issueStore, issueFilter: issueFilterStore, issueDetail: issueDetailStore } = useMobxStore();
|
||||
const {
|
||||
issue: issueStore,
|
||||
issueFilter: issueFilterStore,
|
||||
issueDetail: issueDetailStore,
|
||||
issueCalendarView: issueCalendarViewStore,
|
||||
} = useMobxStore();
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = router.query;
|
||||
|
||||
// TODO: add drag and drop functionality
|
||||
const onDragEnd = (result: DropResult) => {
|
||||
if (!result) return;
|
||||
|
||||
@ -26,7 +30,7 @@ export const CalendarLayout: React.FC = observer(() => {
|
||||
// return if dropped on the same date
|
||||
if (result.destination.droppableId === result.source.droppableId) return;
|
||||
|
||||
// issueKanBanViewStore?.handleDragDrop(result.source, result.destination);
|
||||
issueCalendarViewStore?.handleDragDrop(result.source, result.destination);
|
||||
};
|
||||
|
||||
const issues = issueStore.getIssues;
|
||||
|
@ -15,12 +15,12 @@ export const ProjectViewCalendarLayout: React.FC = observer(() => {
|
||||
projectViewIssues: projectViewIssuesStore,
|
||||
issueFilter: issueFilterStore,
|
||||
issueDetail: issueDetailStore,
|
||||
projectViewIssueCalendarView: projectViewIssueCalendarViewStore,
|
||||
} = useMobxStore();
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = router.query;
|
||||
|
||||
// TODO: add drag and drop functionality
|
||||
const onDragEnd = (result: DropResult) => {
|
||||
if (!result) return;
|
||||
|
||||
@ -30,7 +30,7 @@ export const ProjectViewCalendarLayout: React.FC = observer(() => {
|
||||
// return if dropped on the same date
|
||||
if (result.destination.droppableId === result.source.droppableId) return;
|
||||
|
||||
// issueKanBanViewStore?.handleDragDrop(result.source, result.destination);
|
||||
projectViewIssueCalendarViewStore?.handleDragDrop(result.source, result.destination);
|
||||
};
|
||||
|
||||
const issues = projectViewIssuesStore.getIssues;
|
||||
|
89
web/store/cycle/cycle_issue_calendar_view.store.ts
Normal file
89
web/store/cycle/cycle_issue_calendar_view.store.ts
Normal file
@ -0,0 +1,89 @@
|
||||
import { action, makeObservable, runInAction } from "mobx";
|
||||
// types
|
||||
import { RootStore } from "../root";
|
||||
import { IIssueType } from "./cycle_issue.store";
|
||||
|
||||
export interface ICycleIssueCalendarViewStore {
|
||||
// actions
|
||||
handleDragDrop: (source: any, destination: any) => void;
|
||||
}
|
||||
|
||||
export class CycleIssueCalendarViewStore implements ICycleIssueCalendarViewStore {
|
||||
// root store
|
||||
rootStore;
|
||||
|
||||
constructor(_rootStore: RootStore) {
|
||||
makeObservable(this, {
|
||||
// actions
|
||||
handleDragDrop: action,
|
||||
});
|
||||
|
||||
this.rootStore = _rootStore;
|
||||
}
|
||||
|
||||
handleDragDrop = async (source: any, destination: any) => {
|
||||
const workspaceSlug = this.rootStore?.workspace?.workspaceSlug;
|
||||
const projectId = this.rootStore?.project?.projectId;
|
||||
const cycleId = this.rootStore?.cycle?.cycleId;
|
||||
const issueType: IIssueType | null = this.rootStore?.cycleIssue?.getIssueType;
|
||||
const issueLayout = this.rootStore?.issueFilter?.userDisplayFilters?.layout || null;
|
||||
const currentIssues: any = this.rootStore.cycleIssue.getIssues;
|
||||
|
||||
if (workspaceSlug && projectId && cycleId && issueType && issueLayout === "calendar" && currentIssues) {
|
||||
// update issue payload
|
||||
let updateIssue: any = {
|
||||
workspaceSlug: workspaceSlug,
|
||||
projectId: projectId,
|
||||
};
|
||||
|
||||
const droppableSourceColumnId = source.droppableId;
|
||||
const droppableDestinationColumnId = destination.droppableId;
|
||||
|
||||
if (droppableSourceColumnId === droppableDestinationColumnId) return;
|
||||
|
||||
if (droppableSourceColumnId != droppableDestinationColumnId) {
|
||||
// horizontal
|
||||
const _sourceIssues = currentIssues[droppableSourceColumnId];
|
||||
let _destinationIssues = currentIssues[droppableDestinationColumnId] || [];
|
||||
|
||||
const [removed] = _sourceIssues.splice(source.index, 1);
|
||||
|
||||
if (_destinationIssues && _destinationIssues.length > 0)
|
||||
_destinationIssues.splice(destination.index, 0, {
|
||||
...removed,
|
||||
target_date: droppableDestinationColumnId,
|
||||
});
|
||||
else _destinationIssues = [..._destinationIssues, { ...removed, target_date: droppableDestinationColumnId }];
|
||||
|
||||
updateIssue = { ...updateIssue, issueId: removed?.id, target_date: droppableDestinationColumnId };
|
||||
|
||||
currentIssues[droppableSourceColumnId] = _sourceIssues;
|
||||
currentIssues[droppableDestinationColumnId] = _destinationIssues;
|
||||
}
|
||||
|
||||
const reorderedIssues = {
|
||||
...this.rootStore?.cycleIssue.issues,
|
||||
[cycleId]: {
|
||||
...this.rootStore?.cycleIssue.issues?.[cycleId],
|
||||
[issueType]: {
|
||||
...this.rootStore?.cycleIssue.issues?.[cycleId]?.[issueType],
|
||||
[issueType]: currentIssues,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
runInAction(() => {
|
||||
this.rootStore.cycleIssue.issues = { ...reorderedIssues };
|
||||
});
|
||||
|
||||
this.rootStore.issueDetail?.updateIssue(
|
||||
updateIssue.workspaceSlug,
|
||||
updateIssue.projectId,
|
||||
updateIssue.issueId,
|
||||
updateIssue
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
};
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
export * from "./cycle_issue_filters.store";
|
||||
export * from "./cycle_issue_kanban_view.store";
|
||||
export * from "./cycle_issue_calendar_view.store";
|
||||
export * from "./cycle_issue.store";
|
||||
export * from "./cycles.store";
|
||||
|
@ -2,4 +2,5 @@ export * from "./issue_detail.store";
|
||||
export * from "./issue_draft.store";
|
||||
export * from "./issue_filters.store";
|
||||
export * from "./issue_kanban_view.store";
|
||||
export * from "./issue_calendar_view.store";
|
||||
export * from "./issue.store";
|
||||
|
88
web/store/issue/issue_calendar_view.store.ts
Normal file
88
web/store/issue/issue_calendar_view.store.ts
Normal file
@ -0,0 +1,88 @@
|
||||
import { action, makeObservable, runInAction } from "mobx";
|
||||
// types
|
||||
import { RootStore } from "../root";
|
||||
import { IIssueType } from "./issue.store";
|
||||
|
||||
export interface IIssueCalendarViewStore {
|
||||
// actions
|
||||
handleDragDrop: (source: any, destination: any) => void;
|
||||
}
|
||||
|
||||
export class IssueCalendarViewStore implements IIssueCalendarViewStore {
|
||||
// root store
|
||||
rootStore;
|
||||
|
||||
constructor(_rootStore: RootStore) {
|
||||
makeObservable(this, {
|
||||
// actions
|
||||
handleDragDrop: action,
|
||||
});
|
||||
|
||||
this.rootStore = _rootStore;
|
||||
}
|
||||
|
||||
handleDragDrop = async (source: any, destination: any) => {
|
||||
const workspaceSlug = this.rootStore?.workspace?.workspaceSlug;
|
||||
const projectId = this.rootStore?.project?.projectId;
|
||||
const issueType: IIssueType | null = this.rootStore?.issue?.getIssueType;
|
||||
const issueLayout = this.rootStore?.issueFilter?.userDisplayFilters?.layout || null;
|
||||
const currentIssues: any = this.rootStore.issue.getIssues;
|
||||
|
||||
if (workspaceSlug && projectId && issueType && issueLayout === "calendar" && currentIssues) {
|
||||
// update issue payload
|
||||
let updateIssue: any = {
|
||||
workspaceSlug: workspaceSlug,
|
||||
projectId: projectId,
|
||||
};
|
||||
|
||||
const droppableSourceColumnId = source.droppableId;
|
||||
const droppableDestinationColumnId = destination.droppableId;
|
||||
|
||||
if (droppableSourceColumnId === droppableDestinationColumnId) return;
|
||||
|
||||
// horizontal
|
||||
if (droppableSourceColumnId != droppableDestinationColumnId) {
|
||||
const _sourceIssues = currentIssues[droppableSourceColumnId];
|
||||
let _destinationIssues = currentIssues[droppableDestinationColumnId] || [];
|
||||
|
||||
const [removed] = _sourceIssues.splice(source.index, 1);
|
||||
|
||||
if (_destinationIssues && _destinationIssues.length > 0)
|
||||
_destinationIssues.splice(destination.index, 0, {
|
||||
...removed,
|
||||
target_date: droppableDestinationColumnId,
|
||||
});
|
||||
else _destinationIssues = [..._destinationIssues, { ...removed, target_date: droppableDestinationColumnId }];
|
||||
|
||||
updateIssue = { ...updateIssue, issueId: removed?.id, target_date: droppableDestinationColumnId };
|
||||
|
||||
currentIssues[droppableSourceColumnId] = _sourceIssues;
|
||||
currentIssues[droppableDestinationColumnId] = _destinationIssues;
|
||||
}
|
||||
|
||||
const reorderedIssues = {
|
||||
...this.rootStore?.issue.issues,
|
||||
[projectId]: {
|
||||
...this.rootStore?.issue.issues?.[projectId],
|
||||
[issueType]: {
|
||||
...this.rootStore?.issue.issues?.[projectId]?.[issueType],
|
||||
[issueType]: currentIssues,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
runInAction(() => {
|
||||
this.rootStore.issue.issues = { ...reorderedIssues };
|
||||
});
|
||||
|
||||
this.rootStore.issueDetail?.updateIssue(
|
||||
updateIssue.workspaceSlug,
|
||||
updateIssue.projectId,
|
||||
updateIssue.issueId,
|
||||
updateIssue
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
};
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
export * from "./module_filters.store";
|
||||
export * from "./module_issue_kanban_view.store";
|
||||
export * from "./module_issue_calendar_view.store";
|
||||
export * from "./module_issue.store";
|
||||
export * from "./modules.store";
|
||||
|
89
web/store/module/module_issue_calendar_view.store.ts
Normal file
89
web/store/module/module_issue_calendar_view.store.ts
Normal file
@ -0,0 +1,89 @@
|
||||
import { action, makeObservable, runInAction } from "mobx";
|
||||
// types
|
||||
import { RootStore } from "../root";
|
||||
import { IIssueType } from "./module_issue.store";
|
||||
|
||||
export interface IModuleIssueCalendarViewStore {
|
||||
// actions
|
||||
handleDragDrop: (source: any, destination: any) => void;
|
||||
}
|
||||
|
||||
export class ModuleIssueCalendarViewStore implements IModuleIssueCalendarViewStore {
|
||||
// root store
|
||||
rootStore;
|
||||
|
||||
constructor(_rootStore: RootStore) {
|
||||
makeObservable(this, {
|
||||
// actions
|
||||
handleDragDrop: action,
|
||||
});
|
||||
|
||||
this.rootStore = _rootStore;
|
||||
}
|
||||
|
||||
handleDragDrop = async (source: any, destination: any) => {
|
||||
const workspaceSlug = this.rootStore?.workspace?.workspaceSlug;
|
||||
const projectId = this.rootStore?.project?.projectId;
|
||||
const moduleId = this.rootStore?.module?.moduleId;
|
||||
const issueType: IIssueType | null = this.rootStore?.moduleIssue?.getIssueType;
|
||||
const issueLayout = this.rootStore?.issueFilter?.userDisplayFilters?.layout || null;
|
||||
const currentIssues: any = this.rootStore.moduleIssue.getIssues;
|
||||
|
||||
if (workspaceSlug && projectId && moduleId && issueType && issueLayout === "calendar" && currentIssues) {
|
||||
// update issue payload
|
||||
let updateIssue: any = {
|
||||
workspaceSlug: workspaceSlug,
|
||||
projectId: projectId,
|
||||
};
|
||||
|
||||
const droppableSourceColumnId = source.droppableId;
|
||||
const droppableDestinationColumnId = destination.droppableId;
|
||||
|
||||
if (droppableSourceColumnId === droppableDestinationColumnId) return;
|
||||
|
||||
if (droppableSourceColumnId != droppableDestinationColumnId) {
|
||||
// horizontal
|
||||
const _sourceIssues = currentIssues[droppableSourceColumnId];
|
||||
let _destinationIssues = currentIssues[droppableDestinationColumnId] || [];
|
||||
|
||||
const [removed] = _sourceIssues.splice(source.index, 1);
|
||||
|
||||
if (_destinationIssues && _destinationIssues.length > 0)
|
||||
_destinationIssues.splice(destination.index, 0, {
|
||||
...removed,
|
||||
target_date: droppableDestinationColumnId,
|
||||
});
|
||||
else _destinationIssues = [..._destinationIssues, { ...removed, target_date: droppableDestinationColumnId }];
|
||||
|
||||
updateIssue = { ...updateIssue, issueId: removed?.id, target_date: droppableDestinationColumnId };
|
||||
|
||||
currentIssues[droppableSourceColumnId] = _sourceIssues;
|
||||
currentIssues[droppableDestinationColumnId] = _destinationIssues;
|
||||
}
|
||||
|
||||
const reorderedIssues = {
|
||||
...this.rootStore?.moduleIssue.issues,
|
||||
[moduleId]: {
|
||||
...this.rootStore?.moduleIssue.issues?.[moduleId],
|
||||
[issueType]: {
|
||||
...this.rootStore?.moduleIssue.issues?.[moduleId]?.[issueType],
|
||||
[issueType]: currentIssues,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
runInAction(() => {
|
||||
this.rootStore.moduleIssue.issues = { ...reorderedIssues };
|
||||
});
|
||||
|
||||
this.rootStore.issueDetail?.updateIssue(
|
||||
updateIssue.workspaceSlug,
|
||||
updateIssue.projectId,
|
||||
updateIssue.issueId,
|
||||
updateIssue
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
};
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
export * from "./project_view_filters.store";
|
||||
export * from "./project_view_issues.store";
|
||||
export * from "./project_views.store";
|
||||
|
||||
export * from "./project_view_issue_calendar_view.store";
|
||||
|
@ -0,0 +1,89 @@
|
||||
import { action, makeObservable, runInAction } from "mobx";
|
||||
// types
|
||||
import { RootStore } from "../root";
|
||||
import { IIssueType } from "./project_view_issues.store";
|
||||
|
||||
export interface IProjectViewIssueCalendarViewStore {
|
||||
// actions
|
||||
handleDragDrop: (source: any, destination: any) => void;
|
||||
}
|
||||
|
||||
export class ProjectViewIssueCalendarViewStore implements IProjectViewIssueCalendarViewStore {
|
||||
// root store
|
||||
rootStore;
|
||||
|
||||
constructor(_rootStore: RootStore) {
|
||||
makeObservable(this, {
|
||||
// actions
|
||||
handleDragDrop: action,
|
||||
});
|
||||
|
||||
this.rootStore = _rootStore;
|
||||
}
|
||||
|
||||
handleDragDrop = async (source: any, destination: any) => {
|
||||
const workspaceSlug = this.rootStore?.workspace?.workspaceSlug;
|
||||
const projectId = this.rootStore?.project?.projectId;
|
||||
const viewId = this.rootStore?.projectViews?.viewId;
|
||||
const issueType: IIssueType | null = this.rootStore?.projectViewIssues?.getIssueType;
|
||||
const issueLayout = this.rootStore?.issueFilter?.userDisplayFilters?.layout || null;
|
||||
const currentIssues: any = this.rootStore.projectViewIssues.getIssues;
|
||||
|
||||
if (workspaceSlug && projectId && viewId && issueType && issueLayout === "calendar" && currentIssues) {
|
||||
// update issue payload
|
||||
let updateIssue: any = {
|
||||
workspaceSlug: workspaceSlug,
|
||||
projectId: projectId,
|
||||
};
|
||||
|
||||
const droppableSourceColumnId = source.droppableId;
|
||||
const droppableDestinationColumnId = destination.droppableId;
|
||||
|
||||
if (droppableSourceColumnId === droppableDestinationColumnId) return;
|
||||
|
||||
if (droppableSourceColumnId != droppableDestinationColumnId) {
|
||||
// horizontal
|
||||
const _sourceIssues = currentIssues[droppableSourceColumnId];
|
||||
let _destinationIssues = currentIssues[droppableDestinationColumnId] || [];
|
||||
|
||||
const [removed] = _sourceIssues.splice(source.index, 1);
|
||||
|
||||
if (_destinationIssues && _destinationIssues.length > 0)
|
||||
_destinationIssues.splice(destination.index, 0, {
|
||||
...removed,
|
||||
target_date: droppableDestinationColumnId,
|
||||
});
|
||||
else _destinationIssues = [..._destinationIssues, { ...removed, target_date: droppableDestinationColumnId }];
|
||||
|
||||
updateIssue = { ...updateIssue, issueId: removed?.id, target_date: droppableDestinationColumnId };
|
||||
|
||||
currentIssues[droppableSourceColumnId] = _sourceIssues;
|
||||
currentIssues[droppableDestinationColumnId] = _destinationIssues;
|
||||
}
|
||||
|
||||
const reorderedIssues = {
|
||||
...this.rootStore?.projectViewIssues.viewIssues,
|
||||
[viewId]: {
|
||||
...this.rootStore?.projectViewIssues.viewIssues?.[viewId],
|
||||
[issueType]: {
|
||||
...this.rootStore?.projectViewIssues.viewIssues?.[viewId]?.[issueType],
|
||||
[issueType]: currentIssues,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
runInAction(() => {
|
||||
this.rootStore.projectViewIssues.viewIssues = { ...reorderedIssues };
|
||||
});
|
||||
|
||||
this.rootStore.issueDetail?.updateIssue(
|
||||
updateIssue.workspaceSlug,
|
||||
updateIssue.projectId,
|
||||
updateIssue.issueId,
|
||||
updateIssue
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
};
|
||||
}
|
@ -6,10 +6,18 @@ import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
|
||||
import { sortArrayByDate, sortArrayByPriority } from "constants/kanban-helpers";
|
||||
// types
|
||||
import { RootStore } from "../root";
|
||||
import { IIssueGroupWithSubGroupsStructure, IIssueGroupedStructure, IIssueUnGroupedStructure } from "store/issue";
|
||||
import { IIssue, IIssueFilterOptions } from "types";
|
||||
import { IBlockUpdateData } from "components/gantt-chart";
|
||||
|
||||
export type IIssueType = "grouped" | "groupWithSubGroups" | "ungrouped";
|
||||
export type IIssueGroupedStructure = { [group_id: string]: IIssue[] };
|
||||
export type IIssueGroupWithSubGroupsStructure = {
|
||||
[group_id: string]: {
|
||||
[sub_group_id: string]: IIssue[];
|
||||
};
|
||||
};
|
||||
export type IIssueUnGroupedStructure = IIssue[];
|
||||
|
||||
export interface IProjectViewIssuesStore {
|
||||
// states
|
||||
loader: boolean;
|
||||
@ -37,6 +45,7 @@ export interface IProjectViewIssuesStore {
|
||||
|
||||
// computed
|
||||
getIssues: IIssueGroupedStructure | IIssueGroupWithSubGroupsStructure | IIssueUnGroupedStructure | null;
|
||||
getIssueType: IIssueType | null;
|
||||
}
|
||||
|
||||
export class ProjectViewIssuesStore implements IProjectViewIssuesStore {
|
||||
@ -75,6 +84,7 @@ export class ProjectViewIssuesStore implements IProjectViewIssuesStore {
|
||||
fetchViewIssues: action,
|
||||
|
||||
// computed
|
||||
getIssueType: computed,
|
||||
getIssues: computed,
|
||||
});
|
||||
|
||||
@ -108,6 +118,26 @@ export class ProjectViewIssuesStore implements IProjectViewIssuesStore {
|
||||
return computedFilters;
|
||||
};
|
||||
|
||||
get getIssueType() {
|
||||
const groupedLayouts = ["kanban", "list", "calendar"];
|
||||
const ungroupedLayouts = ["spreadsheet", "gantt_chart"];
|
||||
|
||||
const issueLayout = this.rootStore?.issueFilter?.userDisplayFilters?.layout || null;
|
||||
const issueSubGroup = this.rootStore?.issueFilter?.userDisplayFilters?.sub_group_by || null;
|
||||
|
||||
if (!issueLayout) return null;
|
||||
|
||||
const _issueState = groupedLayouts.includes(issueLayout)
|
||||
? issueSubGroup
|
||||
? "groupWithSubGroups"
|
||||
: "grouped"
|
||||
: ungroupedLayouts.includes(issueLayout)
|
||||
? "ungrouped"
|
||||
: null;
|
||||
|
||||
return _issueState || null;
|
||||
}
|
||||
|
||||
get getIssues() {
|
||||
const viewId: string | null = this.rootStore.projectViews.viewId;
|
||||
const issueType = this.rootStore.issue.getIssueType;
|
||||
|
@ -12,6 +12,8 @@ import {
|
||||
IssueDetailStore,
|
||||
IssueFilterStore,
|
||||
IssueKanBanViewStore,
|
||||
IIssueCalendarViewStore,
|
||||
IssueCalendarViewStore,
|
||||
IssueStore,
|
||||
} from "store/issue";
|
||||
import { IWorkspaceFilterStore, IWorkspaceStore, WorkspaceFilterStore, WorkspaceStore } from "store/workspace";
|
||||
@ -24,6 +26,8 @@ import {
|
||||
ModuleFilterStore,
|
||||
ModuleIssueKanBanViewStore,
|
||||
ModuleIssueStore,
|
||||
IModuleIssueCalendarViewStore,
|
||||
ModuleIssueCalendarViewStore,
|
||||
ModuleStore,
|
||||
} from "store/module";
|
||||
import {
|
||||
@ -33,6 +37,8 @@ import {
|
||||
CycleStore,
|
||||
ICycleIssueFilterStore,
|
||||
ICycleIssueKanBanViewStore,
|
||||
ICycleIssueCalendarViewStore,
|
||||
CycleIssueCalendarViewStore,
|
||||
ICycleIssueStore,
|
||||
ICycleStore,
|
||||
} from "store/cycle";
|
||||
@ -43,6 +49,8 @@ import {
|
||||
ProjectViewFiltersStore,
|
||||
ProjectViewIssuesStore,
|
||||
ProjectViewsStore,
|
||||
IProjectViewIssueCalendarViewStore,
|
||||
ProjectViewIssueCalendarViewStore,
|
||||
} from "store/project-view";
|
||||
import CalendarStore, { ICalendarStore } from "store/calendar.store";
|
||||
import {
|
||||
@ -95,19 +103,23 @@ export class RootStore {
|
||||
moduleIssue: IModuleIssueStore;
|
||||
moduleFilter: IModuleFilterStore;
|
||||
moduleIssueKanBanView: IModuleIssueKanBanViewStore;
|
||||
moduleIssueCalendarView: IModuleIssueCalendarViewStore;
|
||||
|
||||
cycle: ICycleStore;
|
||||
cycleIssue: ICycleIssueStore;
|
||||
cycleIssueFilter: ICycleIssueFilterStore;
|
||||
cycleIssueKanBanView: ICycleIssueKanBanViewStore;
|
||||
cycleIssueCalendarView: ICycleIssueCalendarViewStore;
|
||||
|
||||
projectViews: IProjectViewsStore;
|
||||
projectViewIssues: IProjectViewIssuesStore;
|
||||
projectViewFilters: IProjectViewFiltersStore;
|
||||
projectViewIssueCalendarView: IProjectViewIssueCalendarViewStore;
|
||||
|
||||
issueFilter: IIssueFilterStore;
|
||||
issueDetail: IIssueDetailStore;
|
||||
issueKanBanView: IIssueKanBanViewStore;
|
||||
issueCalendarView: IIssueCalendarViewStore;
|
||||
draftIssuesStore: DraftIssuesStore;
|
||||
|
||||
calendar: ICalendarStore;
|
||||
@ -145,20 +157,24 @@ export class RootStore {
|
||||
this.moduleIssue = new ModuleIssueStore(this);
|
||||
this.moduleFilter = new ModuleFilterStore(this);
|
||||
this.moduleIssueKanBanView = new ModuleIssueKanBanViewStore(this);
|
||||
this.moduleIssueCalendarView = new ModuleIssueCalendarViewStore(this);
|
||||
|
||||
this.cycle = new CycleStore(this);
|
||||
this.cycleIssue = new CycleIssueStore(this);
|
||||
this.cycleIssueFilter = new CycleIssueFilterStore(this);
|
||||
this.cycleIssueKanBanView = new CycleIssueKanBanViewStore(this);
|
||||
this.cycleIssueCalendarView = new CycleIssueCalendarViewStore(this);
|
||||
|
||||
this.projectViews = new ProjectViewsStore(this);
|
||||
this.projectViewIssues = new ProjectViewIssuesStore(this);
|
||||
this.projectViewFilters = new ProjectViewFiltersStore(this);
|
||||
this.projectViewIssueCalendarView = new ProjectViewIssueCalendarViewStore(this);
|
||||
|
||||
this.issue = new IssueStore(this);
|
||||
this.issueFilter = new IssueFilterStore(this);
|
||||
this.issueDetail = new IssueDetailStore(this);
|
||||
this.issueKanBanView = new IssueKanBanViewStore(this);
|
||||
this.issueCalendarView = new IssueCalendarViewStore(this);
|
||||
this.draftIssuesStore = new DraftIssuesStore(this);
|
||||
|
||||
this.calendar = new CalendarStore(this);
|
||||
|
Loading…
Reference in New Issue
Block a user