Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: implemented drag and drop between dates for project issues, cycle, module, and project views for calendar layout #2535

Merged
merged 2 commits into from
Oct 25, 2023
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
61 changes: 36 additions & 25 deletions web/components/issues/issue-layouts/calendar/day-tile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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>
</>
);
});
58 changes: 31 additions & 27 deletions web/components/issues/issue-layouts/calendar/issue-blocks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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>
</>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand Down
89 changes: 89 additions & 0 deletions web/store/cycle/cycle_issue_calendar_view.store.ts
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions web/store/cycle/index.ts
Original file line number Diff line number Diff line change
@@ -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";
1 change: 1 addition & 0 deletions web/store/issue/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Loading
Loading