fix: drag and drop function (#815)

* fix: kanban drag and drop

* fix: kanban board issue dnd mutation
This commit is contained in:
Aaryan Khandelwal 2023-04-13 19:09:55 +05:30 committed by GitHub
parent 6de94efc7d
commit 3fa6185b63
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 123 additions and 44 deletions

View File

@ -108,7 +108,9 @@ export const SingleBoard: React.FC<Props> = ({
key={issue.id} key={issue.id}
draggableId={issue.id} draggableId={issue.id}
index={index} index={index}
isDragDisabled={isNotAllowed || selectedGroup === "created_by"} isDragDisabled={
isNotAllowed || selectedGroup === "created_by" || selectedGroup === "labels"
}
> >
{(provided, snapshot) => ( {(provided, snapshot) => (
<SingleBoardIssue <SingleBoardIssue

View File

@ -50,7 +50,6 @@ import {
MODULE_ISSUES_WITH_PARAMS, MODULE_ISSUES_WITH_PARAMS,
PROJECT_ISSUES_LIST_WITH_PARAMS, PROJECT_ISSUES_LIST_WITH_PARAMS,
} from "constants/fetch-keys"; } from "constants/fetch-keys";
import useEstimateOption from "hooks/use-estimate-option";
type Props = { type Props = {
type?: string; type?: string;
@ -93,8 +92,6 @@ export const SingleBoardIssue: React.FC<Props> = ({
const { orderBy, params } = useIssuesView(); const { orderBy, params } = useIssuesView();
const { estimateValue } = useEstimateOption(issue.estimate_point);
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, cycleId, moduleId } = router.query; const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
@ -113,7 +110,14 @@ export const SingleBoardIssue: React.FC<Props> = ({
>( >(
CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params), CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params),
(prevData) => (prevData) =>
handleIssuesMutation(formData, groupTitle ?? "", selectedGroup, index, prevData), handleIssuesMutation(
formData,
groupTitle ?? "",
selectedGroup,
index,
orderBy,
prevData
),
false false
); );
else if (moduleId) else if (moduleId)
@ -125,10 +129,17 @@ export const SingleBoardIssue: React.FC<Props> = ({
>( >(
MODULE_ISSUES_WITH_PARAMS(moduleId as string), MODULE_ISSUES_WITH_PARAMS(moduleId as string),
(prevData) => (prevData) =>
handleIssuesMutation(formData, groupTitle ?? "", selectedGroup, index, prevData), handleIssuesMutation(
formData,
groupTitle ?? "",
selectedGroup,
index,
orderBy,
prevData
),
false false
); );
else else {
mutate< mutate<
| { | {
[key: string]: IIssue[]; [key: string]: IIssue[];
@ -136,10 +147,21 @@ export const SingleBoardIssue: React.FC<Props> = ({
| IIssue[] | IIssue[]
>( >(
PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params), PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params),
(prevData) => (prevData) => {
handleIssuesMutation(formData, groupTitle ?? "", selectedGroup, index, prevData), if (!prevData) return prevData;
return handleIssuesMutation(
formData,
groupTitle ?? "",
selectedGroup,
index,
orderBy,
prevData
);
},
false false
); );
}
issuesService issuesService
.patchIssue(workspaceSlug as string, projectId as string, issue.id, formData) .patchIssue(workspaceSlug as string, projectId as string, issue.id, formData)
@ -156,7 +178,18 @@ export const SingleBoardIssue: React.FC<Props> = ({
console.log(error); console.log(error);
}); });
}, },
[workspaceSlug, projectId, cycleId, moduleId, issue, groupTitle, index, selectedGroup, params] [
workspaceSlug,
projectId,
cycleId,
moduleId,
issue,
groupTitle,
index,
selectedGroup,
orderBy,
params,
]
); );
const getStyle = ( const getStyle = (

View File

@ -48,6 +48,7 @@ import {
} from "constants/fetch-keys"; } from "constants/fetch-keys";
// image // image
import emptyCycle from "public/empty-state/empty-cycle.svg"; import emptyCycle from "public/empty-state/empty-cycle.svg";
import { orderArrayBy } from "helpers/array.helper";
type Props = { type Props = {
type?: "issue" | "cycle" | "module"; type?: "issue" | "cycle" | "module";
@ -208,8 +209,8 @@ export const IssuesView: React.FC<Props> = ({
return { return {
...prevData, ...prevData,
[sourceGroup]: sourceGroupArray, [sourceGroup]: orderArrayBy(sourceGroupArray, orderBy),
[destinationGroup]: destinationGroupArray, [destinationGroup]: orderArrayBy(destinationGroupArray, orderBy),
}; };
}, },
false false
@ -230,8 +231,8 @@ export const IssuesView: React.FC<Props> = ({
return { return {
...prevData, ...prevData,
[sourceGroup]: sourceGroupArray, [sourceGroup]: orderArrayBy(sourceGroupArray, orderBy),
[destinationGroup]: destinationGroupArray, [destinationGroup]: orderArrayBy(destinationGroupArray, orderBy),
}; };
}, },
false false
@ -250,8 +251,8 @@ export const IssuesView: React.FC<Props> = ({
return { return {
...prevData, ...prevData,
[sourceGroup]: sourceGroupArray, [sourceGroup]: orderArrayBy(sourceGroupArray, orderBy),
[destinationGroup]: destinationGroupArray, [destinationGroup]: orderArrayBy(destinationGroupArray, orderBy),
}; };
}, },
false false

View File

@ -29,7 +29,7 @@ import {
TrashIcon, TrashIcon,
XMarkIcon, XMarkIcon,
ArrowTopRightOnSquareIcon, ArrowTopRightOnSquareIcon,
PaperClipIcon PaperClipIcon,
} from "@heroicons/react/24/outline"; } from "@heroicons/react/24/outline";
// helpers // helpers
import { copyTextToClipboard, truncateText } from "helpers/string.helper"; import { copyTextToClipboard, truncateText } from "helpers/string.helper";
@ -82,7 +82,7 @@ export const SingleListIssue: React.FC<Props> = ({
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
const { groupByProperty: selectedGroup, params } = useIssueView(); const { groupByProperty: selectedGroup, orderBy, params } = useIssueView();
const partialUpdateIssue = useCallback( const partialUpdateIssue = useCallback(
(formData: Partial<IIssue>) => { (formData: Partial<IIssue>) => {
@ -97,7 +97,14 @@ export const SingleListIssue: React.FC<Props> = ({
>( >(
CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params), CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params),
(prevData) => (prevData) =>
handleIssuesMutation(formData, groupTitle ?? "", selectedGroup, index, prevData), handleIssuesMutation(
formData,
groupTitle ?? "",
selectedGroup,
index,
orderBy,
prevData
),
false false
); );
@ -110,7 +117,14 @@ export const SingleListIssue: React.FC<Props> = ({
>( >(
MODULE_ISSUES_WITH_PARAMS(moduleId as string, params), MODULE_ISSUES_WITH_PARAMS(moduleId as string, params),
(prevData) => (prevData) =>
handleIssuesMutation(formData, groupTitle ?? "", selectedGroup, index, prevData), handleIssuesMutation(
formData,
groupTitle ?? "",
selectedGroup,
index,
orderBy,
prevData
),
false false
); );
@ -122,7 +136,7 @@ export const SingleListIssue: React.FC<Props> = ({
>( >(
PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params), PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params),
(prevData) => (prevData) =>
handleIssuesMutation(formData, groupTitle ?? "", selectedGroup, index, prevData), handleIssuesMutation(formData, groupTitle ?? "", selectedGroup, index, orderBy, prevData),
false false
); );
@ -138,7 +152,18 @@ export const SingleListIssue: React.FC<Props> = ({
} else mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params)); } else mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params));
}); });
}, },
[workspaceSlug, projectId, cycleId, moduleId, issue, groupTitle, index, selectedGroup, params] [
workspaceSlug,
projectId,
cycleId,
moduleId,
issue,
groupTitle,
index,
selectedGroup,
orderBy,
params,
]
); );
const handleCopyText = () => { const handleCopyText = () => {

View File

@ -37,6 +37,7 @@ export const FILTER_ISSUE_OPTIONS: Array<{
}, },
]; ];
import { orderArrayBy } from "helpers/array.helper";
import { IIssue, TIssueGroupByOptions, TIssueOrderByOptions } from "types"; import { IIssue, TIssueGroupByOptions, TIssueOrderByOptions } from "types";
type THandleIssuesMutation = ( type THandleIssuesMutation = (
@ -44,6 +45,7 @@ type THandleIssuesMutation = (
oldGroupTitle: string, oldGroupTitle: string,
selectedGroupBy: TIssueGroupByOptions, selectedGroupBy: TIssueGroupByOptions,
issueIndex: number, issueIndex: number,
orderBy: TIssueOrderByOptions,
prevData?: prevData?:
| { | {
[key: string]: IIssue[]; [key: string]: IIssue[];
@ -61,6 +63,7 @@ export const handleIssuesMutation: THandleIssuesMutation = (
oldGroupTitle, oldGroupTitle,
selectedGroupBy, selectedGroupBy,
issueIndex, issueIndex,
orderBy,
prevData prevData
) => { ) => {
if (!prevData) return prevData; if (!prevData) return prevData;
@ -89,15 +92,24 @@ export const handleIssuesMutation: THandleIssuesMutation = (
assignees: formData?.assignees_list ?? oldGroup[issueIndex]?.assignees_list, assignees: formData?.assignees_list ?? oldGroup[issueIndex]?.assignees_list,
}; };
oldGroup.splice(issueIndex, 1); if (selectedGroupBy !== Object.keys(formData)[0])
newGroup.push(updatedIssue); return {
...prevData,
[oldGroupTitle ?? ""]: orderArrayBy(
oldGroup.map((i) => (i.id === updatedIssue.id ? updatedIssue : i)),
orderBy
),
};
const groupThatIsUpdated = selectedGroupBy === "priority" ? formData.priority : formData.state; const groupThatIsUpdated = selectedGroupBy === "priority" ? formData.priority : formData.state;
return { return {
...prevData, ...prevData,
[oldGroupTitle ?? ""]: oldGroup, [oldGroupTitle ?? ""]: orderArrayBy(
[groupThatIsUpdated ?? ""]: newGroup, oldGroup.filter((i) => i.id !== updatedIssue.id),
orderBy
),
[groupThatIsUpdated ?? ""]: orderArrayBy([...newGroup, updatedIssue], orderBy),
}; };
} }
}; };

View File

@ -12,7 +12,13 @@ export const orderArrayBy = (
key: string, key: string,
ordering: "ascending" | "descending" = "ascending" ordering: "ascending" | "descending" = "ascending"
) => { ) => {
if (key[0] === "-") {
ordering = "descending";
key = key.slice(1);
}
const innerKey = key.split("."); // split the key by dot const innerKey = key.split("."); // split the key by dot
return array.sort((a, b) => { return array.sort((a, b) => {
const keyA = innerKey.reduce((obj, i) => obj[i], a); // get the value of the inner key const keyA = innerKey.reduce((obj, i) => obj[i], a); // get the value of the inner key
const keyB = innerKey.reduce((obj, i) => obj[i], b); // get the value of the inner key const keyB = innerKey.reduce((obj, i) => obj[i], b); // get the value of the inner key