refactor: removed unnecessary api calls

This commit is contained in:
Aaryan Khandelwal 2023-02-05 22:01:23 +05:30
parent d673aedf48
commit 0e07c1e19f
11 changed files with 182 additions and 211 deletions

View File

@ -34,7 +34,7 @@ type Props = {
}; };
export const SingleBoard: React.FC<Props> = ({ export const SingleBoard: React.FC<Props> = ({
type = "issue", type,
provided, provided,
snapshot, snapshot,
bgColor, bgColor,
@ -117,6 +117,7 @@ export const SingleBoard: React.FC<Props> = ({
{...provided.dragHandleProps} {...provided.dragHandleProps}
> >
<SingleBoardIssue <SingleBoardIssue
type={type}
issue={childIssue} issue={childIssue}
properties={properties} properties={properties}
snapshot={snapshot} snapshot={snapshot}

View File

@ -15,7 +15,6 @@ import { TrashIcon } from "@heroicons/react/24/outline";
// services // services
import issuesService from "services/issues.service"; import issuesService from "services/issues.service";
import stateService from "services/state.service"; import stateService from "services/state.service";
import projectService from "services/project.service";
// components // components
import { AssigneesList, CustomDatePicker } from "components/ui"; import { AssigneesList, CustomDatePicker } from "components/ui";
// helpers // helpers
@ -34,18 +33,11 @@ import {
} from "types"; } from "types";
// common // common
import { PRIORITIES } from "constants/"; import { PRIORITIES } from "constants/";
import { import { STATE_LIST, CYCLE_ISSUES, MODULE_ISSUES, PROJECT_ISSUES_LIST } from "constants/fetch-keys";
STATE_LIST,
PROJECT_DETAILS,
CYCLE_ISSUES,
MODULE_ISSUES,
PROJECT_ISSUES_LIST,
} from "constants/fetch-keys";
import { getPriorityIcon } from "constants/global"; import { getPriorityIcon } from "constants/global";
type Props = { type Props = {
type?: string; type?: string;
typeId?: string;
issue: IIssue; issue: IIssue;
properties: Properties; properties: Properties;
snapshot: DraggableStateSnapshot; snapshot: DraggableStateSnapshot;
@ -57,7 +49,6 @@ type Props = {
export const SingleBoardIssue: React.FC<Props> = ({ export const SingleBoardIssue: React.FC<Props> = ({
type, type,
typeId,
issue, issue,
properties, properties,
snapshot, snapshot,
@ -67,7 +58,7 @@ export const SingleBoardIssue: React.FC<Props> = ({
userAuth, userAuth,
}) => { }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
const { data: states } = useSWR( const { data: states } = useSWR(
workspaceSlug && projectId ? STATE_LIST(projectId as string) : null, workspaceSlug && projectId ? STATE_LIST(projectId as string) : null,
@ -76,19 +67,12 @@ export const SingleBoardIssue: React.FC<Props> = ({
: null : null
); );
const { data: projectDetails } = useSWR(
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
workspaceSlug && projectId
? () => projectService.getProject(workspaceSlug as string, projectId as string)
: null
);
const partialUpdateIssue = (formData: Partial<IIssue>) => { const partialUpdateIssue = (formData: Partial<IIssue>) => {
if (!workspaceSlug || !projectId) return; if (!workspaceSlug || !projectId) return;
if (typeId) { if (cycleId)
mutate<CycleIssueResponse[]>( mutate<CycleIssueResponse[]>(
CYCLE_ISSUES(typeId ?? ""), CYCLE_ISSUES(cycleId as string),
(prevData) => { (prevData) => {
const updatedIssues = (prevData ?? []).map((p) => { const updatedIssues = (prevData ?? []).map((p) => {
if (p.issue_detail.id === issue.id) { if (p.issue_detail.id === issue.id) {
@ -107,8 +91,9 @@ export const SingleBoardIssue: React.FC<Props> = ({
false false
); );
if (moduleId)
mutate<ModuleIssueResponse[]>( mutate<ModuleIssueResponse[]>(
MODULE_ISSUES(typeId ?? ""), MODULE_ISSUES(moduleId as string),
(prevData) => { (prevData) => {
const updatedIssues = (prevData ?? []).map((p) => { const updatedIssues = (prevData ?? []).map((p) => {
if (p.issue_detail.id === issue.id) { if (p.issue_detail.id === issue.id) {
@ -126,7 +111,6 @@ export const SingleBoardIssue: React.FC<Props> = ({
}, },
false false
); );
}
mutate<IssueResponse>( mutate<IssueResponse>(
PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string), PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string),
@ -143,10 +127,14 @@ export const SingleBoardIssue: React.FC<Props> = ({
issuesService issuesService
.patchIssue(workspaceSlug as string, projectId as string, issue.id, formData) .patchIssue(workspaceSlug as string, projectId as string, issue.id, formData)
.then((res) => { .then((res) => {
if (typeId) { mutate(
mutate(CYCLE_ISSUES(typeId ?? "")); cycleId ? CYCLE_ISSUES(cycleId as string) : CYCLE_ISSUES(issue?.issue_cycle?.cycle ?? "")
mutate(MODULE_ISSUES(typeId ?? "")); );
} mutate(
moduleId
? MODULE_ISSUES(moduleId as string)
: MODULE_ISSUES(issue?.issue_module?.module ?? "")
);
mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string)); mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string));
}) })
@ -179,7 +167,7 @@ export const SingleBoardIssue: React.FC<Props> = ({
<a> <a>
{properties.key && ( {properties.key && (
<div className="mb-2 text-xs font-medium text-gray-500"> <div className="mb-2 text-xs font-medium text-gray-500">
{projectDetails?.identifier}-{issue.sequence_id} {issue.project_detail.identifier}-{issue.sequence_id}
</div> </div>
)} )}
<h5 <h5
@ -312,11 +300,6 @@ export const SingleBoardIssue: React.FC<Props> = ({
)} )}
</Listbox> </Listbox>
)} )}
{/* {properties.cycle && !typeId && (
<div className="flex flex-shrink-0 items-center gap-1 rounded border px-2 py-1 text-xs shadow-sm duration-300 hover:bg-gray-100 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500">
{issue.issue_cycle ? issue.issue_cycle.cycle_detail.name : "None"}
</div>
)} */}
{properties.due_date && ( {properties.due_date && (
<div <div
className={`group relative ${ className={`group relative ${

View File

@ -1,27 +1,26 @@
// react
import React, { useState } from "react"; import React, { useState } from "react";
// next
import { useRouter } from "next/router"; import { useRouter } from "next/router";
// swr
import useSWR, { mutate } from "swr"; import useSWR, { mutate } from "swr";
// react hook form // react hook form
import { SubmitHandler, useForm } from "react-hook-form"; import { SubmitHandler, useForm } from "react-hook-form";
// services // headless ui
import { Combobox, Dialog, Transition } from "@headlessui/react"; import { Combobox, Dialog, Transition } from "@headlessui/react";
import { MagnifyingGlassIcon } from "@heroicons/react/24/outline"; // services
import issuesServices from "services/issues.service"; import issuesServices from "services/issues.service";
import projectService from "services/project.service";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
// headless ui
// ui // ui
import { Button } from "components/ui"; import { Button } from "components/ui";
// icons // icons
import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
import { LayerDiagonalIcon } from "components/icons"; import { LayerDiagonalIcon } from "components/icons";
// types // types
import { IIssue, IssueResponse } from "types"; import { IIssue, IssueResponse } from "types";
// fetch keys // fetch keys
import { PROJECT_ISSUES_LIST, PROJECT_DETAILS } from "constants/fetch-keys"; import { PROJECT_ISSUES_LIST } from "constants/fetch-keys";
type FormInput = { type FormInput = {
delete_issue_ids: string[]; delete_issue_ids: string[];
@ -50,13 +49,6 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen }) =>
: null : null
); );
const { data: projectDetails } = useSWR(
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
workspaceSlug && projectId
? () => projectService.getProject(workspaceSlug as string, projectId as string)
: null
);
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
const { const {
@ -213,7 +205,7 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen }) =>
}} }}
/> />
<span className="flex-shrink-0 text-xs text-gray-500"> <span className="flex-shrink-0 text-xs text-gray-500">
{projectDetails?.identifier}-{issue.sequence_id} {issue.project_detail.identifier}-{issue.sequence_id}
</span> </span>
<span>{issue.name}</span> <span>{issue.name}</span>
</div> </div>

View File

@ -1,24 +1,17 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { useRouter } from "next/router";
import useSWR from "swr";
// react-hook-form // react-hook-form
import { Controller, SubmitHandler, useForm } from "react-hook-form"; import { Controller, SubmitHandler, useForm } from "react-hook-form";
// hooks // hooks
import { Combobox, Dialog, Transition } from "@headlessui/react"; import { Combobox, Dialog, Transition } from "@headlessui/react";
import { MagnifyingGlassIcon, RectangleStackIcon } from "@heroicons/react/24/outline"; import { MagnifyingGlassIcon, RectangleStackIcon } from "@heroicons/react/24/outline";
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
// services
import projectService from "services/project.service";
// headless ui // headless ui
// ui // ui
import { Button } from "components/ui"; import { Button } from "components/ui";
import { LayerDiagonalIcon } from "components/icons"; import { LayerDiagonalIcon } from "components/icons";
// types // types
import { IIssue } from "types"; import { IIssue } from "types";
// fetch-keys
import { PROJECT_DETAILS } from "constants/fetch-keys";
type FormInput = { type FormInput = {
issues: string[]; issues: string[];
@ -41,16 +34,6 @@ export const ExistingIssuesListModal: React.FC<Props> = ({
}) => { }) => {
const [query, setQuery] = useState(""); const [query, setQuery] = useState("");
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
const { data: projectDetails } = useSWR(
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
workspaceSlug && projectId
? () => projectService.getProject(workspaceSlug as string, projectId as string)
: null
);
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
const handleClose = () => { const handleClose = () => {
@ -175,7 +158,7 @@ export const ExistingIssuesListModal: React.FC<Props> = ({
}} }}
/> />
<span className="flex-shrink-0 text-xs text-gray-500"> <span className="flex-shrink-0 text-xs text-gray-500">
{projectDetails?.identifier}-{issue.sequence_id} {issue.project_detail.identifier}-{issue.sequence_id}
</span> </span>
{issue.name} {issue.name}
</> </>

View File

@ -10,10 +10,11 @@ import { DropResult } from "react-beautiful-dnd";
import issuesService from "services/issues.service"; import issuesService from "services/issues.service";
import stateService from "services/state.service"; import stateService from "services/state.service";
import projectService from "services/project.service"; import projectService from "services/project.service";
import modulesService from "services/modules.service";
// hooks // hooks
import useIssueView from "hooks/use-issue-view"; import useIssueView from "hooks/use-issue-view";
// components // components
import { AllLists, AllBoards } from "components/core"; import { AllLists, AllBoards, ExistingIssuesListModal } from "components/core";
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues"; import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
// types // types
import { import {
@ -124,6 +125,7 @@ export const IssuesView: React.FC<Props> = ({
}); });
} else { } else {
const draggedItem = groupedByIssues[source.droppableId][source.index]; const draggedItem = groupedByIssues[source.droppableId][source.index];
console.log(draggedItem);
if (source.droppableId !== destination.droppableId) { if (source.droppableId !== destination.droppableId) {
const sourceGroup = source.droppableId; // source group id const sourceGroup = source.droppableId; // source group id
const destinationGroup = destination.droppableId; // destination group id const destinationGroup = destination.droppableId; // destination group id
@ -217,6 +219,7 @@ export const IssuesView: React.FC<Props> = ({
? MODULE_ISSUES(moduleId as string) ? MODULE_ISSUES(moduleId as string)
: MODULE_ISSUES(draggedItem.issue_module?.module ?? "") : MODULE_ISSUES(draggedItem.issue_module?.module ?? "")
); );
mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string)); mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string));
}); });
} else if (selectedGroup === "state_detail.name") { } else if (selectedGroup === "state_detail.name") {
@ -358,6 +361,54 @@ export const IssuesView: React.FC<Props> = ({
setIssueToDelete(issue); setIssueToDelete(issue);
}; };
const removeIssueFromCycle = (bridgeId: string) => {
if (!workspaceSlug || !projectId) return;
mutate<CycleIssueResponse[]>(
CYCLE_ISSUES(cycleId as string),
(prevData) => prevData?.filter((p) => p.id !== bridgeId),
false
);
issuesService
.removeIssueFromCycle(
workspaceSlug as string,
projectId as string,
cycleId as string,
bridgeId
)
.then((res) => {
console.log(res);
})
.catch((e) => {
console.log(e);
});
};
const removeIssueFromModule = (bridgeId: string) => {
if (!workspaceSlug || !projectId) return;
mutate<ModuleIssueResponse[]>(
MODULE_ISSUES(moduleId as string),
(prevData) => prevData?.filter((p) => p.id !== bridgeId),
false
);
modulesService
.removeIssueFromModule(
workspaceSlug as string,
projectId as string,
moduleId as string,
bridgeId
)
.then((res) => {
console.log(res);
})
.catch((e) => {
console.log(e);
});
};
return ( return (
<> <>
<CreateUpdateIssueModal <CreateUpdateIssueModal
@ -385,9 +436,16 @@ export const IssuesView: React.FC<Props> = ({
states={states} states={states}
members={members} members={members}
addIssueToState={addIssueToState} addIssueToState={addIssueToState}
openIssuesListModal={type !== "issue" ? openIssuesListModal : null}
handleEditIssue={handleEditIssue} handleEditIssue={handleEditIssue}
handleDeleteIssue={handleDeleteIssue} handleDeleteIssue={handleDeleteIssue}
openIssuesListModal={type !== "issue" ? openIssuesListModal : null}
removeIssue={
type === "cycle"
? removeIssueFromCycle
: type === "module"
? removeIssueFromModule
: null
}
userAuth={userAuth} userAuth={userAuth}
/> />
) : ( ) : (

View File

@ -12,9 +12,10 @@ type Props = {
states: IState[] | undefined; states: IState[] | undefined;
members: IProjectMember[] | undefined; members: IProjectMember[] | undefined;
addIssueToState: (groupTitle: string, stateId: string | null) => void; addIssueToState: (groupTitle: string, stateId: string | null) => void;
openIssuesListModal?: (() => void) | null;
handleEditIssue: (issue: IIssue) => void; handleEditIssue: (issue: IIssue) => void;
handleDeleteIssue: (issue: IIssue) => void; handleDeleteIssue: (issue: IIssue) => void;
openIssuesListModal?: (() => void) | null;
removeIssue: ((bridgeId: string) => void) | null;
userAuth: UserAuth; userAuth: UserAuth;
}; };
@ -27,6 +28,7 @@ export const AllLists: React.FC<Props> = ({
openIssuesListModal, openIssuesListModal,
handleEditIssue, handleEditIssue,
handleDeleteIssue, handleDeleteIssue,
removeIssue,
userAuth, userAuth,
}) => { }) => {
const { groupedByIssues, groupByProperty: selectedGroup } = useIssueView(issues); const { groupedByIssues, groupByProperty: selectedGroup } = useIssueView(issues);
@ -51,6 +53,7 @@ export const AllLists: React.FC<Props> = ({
handleEditIssue={handleEditIssue} handleEditIssue={handleEditIssue}
handleDeleteIssue={handleDeleteIssue} handleDeleteIssue={handleDeleteIssue}
openIssuesListModal={type !== "issue" ? openIssuesListModal : null} openIssuesListModal={type !== "issue" ? openIssuesListModal : null}
removeIssue={removeIssue}
userAuth={userAuth} userAuth={userAuth}
/> />
); );

View File

@ -1,4 +1,4 @@
import React, { useState } from "react"; import React from "react";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
@ -11,8 +11,6 @@ import { Listbox, Transition } from "@headlessui/react";
import issuesService from "services/issues.service"; import issuesService from "services/issues.service";
import workspaceService from "services/workspace.service"; import workspaceService from "services/workspace.service";
import stateService from "services/state.service"; import stateService from "services/state.service";
// components
import { DeleteIssueModal } from "components/issues";
// ui // ui
import { CustomMenu, CustomSelect, AssigneesList, Avatar, CustomDatePicker } from "components/ui"; import { CustomMenu, CustomSelect, AssigneesList, Avatar, CustomDatePicker } from "components/ui";
// helpers // helpers
@ -42,18 +40,16 @@ import { PRIORITIES } from "constants/";
type Props = { type Props = {
type?: string; type?: string;
typeId?: string;
issue: IIssue; issue: IIssue;
properties: Properties; properties: Properties;
editIssue: () => void; editIssue: () => void;
removeIssue?: () => void; removeIssue?: (() => void) | null;
handleDeleteIssue: (issue: IIssue) => void; handleDeleteIssue: (issue: IIssue) => void;
userAuth: UserAuth; userAuth: UserAuth;
}; };
export const SingleListIssue: React.FC<Props> = ({ export const SingleListIssue: React.FC<Props> = ({
type, type,
typeId,
issue, issue,
properties, properties,
editIssue, editIssue,
@ -62,7 +58,7 @@ export const SingleListIssue: React.FC<Props> = ({
userAuth, userAuth,
}) => { }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
const { data: states } = useSWR( const { data: states } = useSWR(
workspaceSlug && projectId ? STATE_LIST(projectId as string) : null, workspaceSlug && projectId ? STATE_LIST(projectId as string) : null,
@ -79,9 +75,9 @@ export const SingleListIssue: React.FC<Props> = ({
const partialUpdateIssue = (formData: Partial<IIssue>) => { const partialUpdateIssue = (formData: Partial<IIssue>) => {
if (!workspaceSlug || !projectId) return; if (!workspaceSlug || !projectId) return;
if (typeId) { if (cycleId)
mutate<CycleIssueResponse[]>( mutate<CycleIssueResponse[]>(
CYCLE_ISSUES(typeId ?? ""), CYCLE_ISSUES(cycleId as string),
(prevData) => { (prevData) => {
const updatedIssues = (prevData ?? []).map((p) => { const updatedIssues = (prevData ?? []).map((p) => {
if (p.issue_detail.id === issue.id) { if (p.issue_detail.id === issue.id) {
@ -100,8 +96,9 @@ export const SingleListIssue: React.FC<Props> = ({
false false
); );
if (moduleId)
mutate<ModuleIssueResponse[]>( mutate<ModuleIssueResponse[]>(
MODULE_ISSUES(typeId ?? ""), MODULE_ISSUES(moduleId as string),
(prevData) => { (prevData) => {
const updatedIssues = (prevData ?? []).map((p) => { const updatedIssues = (prevData ?? []).map((p) => {
if (p.issue_detail.id === issue.id) { if (p.issue_detail.id === issue.id) {
@ -119,7 +116,6 @@ export const SingleListIssue: React.FC<Props> = ({
}, },
false false
); );
}
mutate<IssueResponse>( mutate<IssueResponse>(
PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string), PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string),
@ -136,10 +132,14 @@ export const SingleListIssue: React.FC<Props> = ({
issuesService issuesService
.patchIssue(workspaceSlug as string, projectId as string, issue.id, formData) .patchIssue(workspaceSlug as string, projectId as string, issue.id, formData)
.then((res) => { .then((res) => {
if (typeId) { mutate(
mutate(CYCLE_ISSUES(typeId ?? "")); cycleId ? CYCLE_ISSUES(cycleId as string) : CYCLE_ISSUES(issue?.issue_cycle?.cycle ?? "")
mutate(MODULE_ISSUES(typeId ?? "")); );
} mutate(
moduleId
? MODULE_ISSUES(moduleId as string)
: MODULE_ISSUES(issue?.issue_module?.module ?? "")
);
mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string)); mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string));
}) })
@ -154,7 +154,7 @@ export const SingleListIssue: React.FC<Props> = ({
<div className="flex items-center justify-between gap-2 px-4 py-3 text-sm"> <div className="flex items-center justify-between gap-2 px-4 py-3 text-sm">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span <span
className={`block h-1.5 w-1.5 flex-shrink-0 rounded-full`} className="block h-1.5 w-1.5 flex-shrink-0 rounded-full"
style={{ style={{
backgroundColor: issue.state_detail.color, backgroundColor: issue.state_detail.color,
}} }}
@ -288,11 +288,6 @@ export const SingleListIssue: React.FC<Props> = ({
))} ))}
</CustomSelect> </CustomSelect>
)} )}
{/* {properties.cycle && !typeId && (
<div className="flex flex-shrink-0 items-center gap-1 rounded border px-2 py-1 text-xs shadow-sm duration-300 hover:bg-gray-100 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500">
{issue.issue_cycle ? issue.issue_cycle.cycle_detail.name : "None"}
</div>
)} */}
{properties.due_date && ( {properties.due_date && (
<div <div
className={`group relative ${ className={`group relative ${
@ -409,7 +404,7 @@ export const SingleListIssue: React.FC<Props> = ({
{type && !isNotAllowed && ( {type && !isNotAllowed && (
<CustomMenu width="auto" ellipsis> <CustomMenu width="auto" ellipsis>
<CustomMenu.MenuItem onClick={editIssue}>Edit</CustomMenu.MenuItem> <CustomMenu.MenuItem onClick={editIssue}>Edit</CustomMenu.MenuItem>
{type !== "issue" && ( {type !== "issue" && removeIssue && (
<CustomMenu.MenuItem onClick={removeIssue}> <CustomMenu.MenuItem onClick={removeIssue}>
<>Remove from {type}</> <>Remove from {type}</>
</CustomMenu.MenuItem> </CustomMenu.MenuItem>

View File

@ -12,6 +12,7 @@ import { ChevronDownIcon, PlusIcon } from "@heroicons/react/24/outline";
import { addSpaceIfCamelCase } from "helpers/string.helper"; import { addSpaceIfCamelCase } from "helpers/string.helper";
// types // types
import { IIssue, IProjectMember, NestedKeyOf, UserAuth } from "types"; import { IIssue, IProjectMember, NestedKeyOf, UserAuth } from "types";
import { CustomMenu } from "components/ui";
type Props = { type Props = {
type?: "issue" | "cycle" | "module"; type?: "issue" | "cycle" | "module";
@ -25,11 +26,12 @@ type Props = {
handleEditIssue: (issue: IIssue) => void; handleEditIssue: (issue: IIssue) => void;
handleDeleteIssue: (issue: IIssue) => void; handleDeleteIssue: (issue: IIssue) => void;
openIssuesListModal?: (() => void) | null; openIssuesListModal?: (() => void) | null;
removeIssue: ((bridgeId: string) => void) | null;
userAuth: UserAuth; userAuth: UserAuth;
}; };
export const SingleList: React.FC<Props> = ({ export const SingleList: React.FC<Props> = ({
type = "issue", type,
groupTitle, groupTitle,
groupedByIssues, groupedByIssues,
selectedGroup, selectedGroup,
@ -38,6 +40,7 @@ export const SingleList: React.FC<Props> = ({
handleEditIssue, handleEditIssue,
handleDeleteIssue, handleDeleteIssue,
openIssuesListModal, openIssuesListModal,
removeIssue,
userAuth, userAuth,
}) => { }) => {
const router = useRouter(); const router = useRouter();
@ -105,11 +108,14 @@ export const SingleList: React.FC<Props> = ({
return ( return (
<SingleListIssue <SingleListIssue
key={issue.id} key={issue.id}
type="issue" type={type}
issue={issue} issue={issue}
properties={properties} properties={properties}
editIssue={() => handleEditIssue(issue)} editIssue={() => handleEditIssue(issue)}
handleDeleteIssue={handleDeleteIssue} handleDeleteIssue={handleDeleteIssue}
removeIssue={() => {
removeIssue && removeIssue(issue.bridge);
}}
userAuth={userAuth} userAuth={userAuth}
/> />
); );
@ -133,7 +139,25 @@ export const SingleList: React.FC<Props> = ({
<PlusIcon className="h-3 w-3" /> <PlusIcon className="h-3 w-3" />
Add issue Add issue
</button> </button>
) : null} ) : (
<CustomMenu
label={
<span className="flex items-center gap-1">
<PlusIcon className="h-3 w-3" />
Add issue
</span>
}
optionsPosition="left"
noBorder
>
<CustomMenu.MenuItem onClick={addIssueToState}>Create new</CustomMenu.MenuItem>
{openIssuesListModal && (
<CustomMenu.MenuItem onClick={openIssuesListModal}>
Add an existing issue
</CustomMenu.MenuItem>
)}
</CustomMenu>
)}
</div> </div>
</div> </div>
)} )}

View File

@ -132,30 +132,6 @@ const SingleCycle: React.FC<UserAuth> = (props) => {
}); });
}; };
const removeIssueFromCycle = (bridgeId: string) => {
if (!workspaceSlug || !projectId) return;
mutate<CycleIssueResponse[]>(
CYCLE_ISSUES(cycleId as string),
(prevData) => prevData?.filter((p) => p.id !== bridgeId),
false
);
issuesServices
.removeIssueFromCycle(
workspaceSlug as string,
projectId as string,
cycleId as string,
bridgeId
)
.then((res) => {
console.log(res);
})
.catch((e) => {
console.log(e);
});
};
return ( return (
<IssueViewContextProvider> <IssueViewContextProvider>
<CreateUpdateIssueModal <CreateUpdateIssueModal
@ -226,15 +202,12 @@ const SingleCycle: React.FC<UserAuth> = (props) => {
{cycleIssuesArray ? ( {cycleIssuesArray ? (
cycleIssuesArray.length > 0 ? ( cycleIssuesArray.length > 0 ? (
<div className={`h-full ${cycleSidebar ? "mr-[24rem]" : ""} duration-300`}> <div className={`h-full ${cycleSidebar ? "mr-[24rem]" : ""} duration-300`}>
{/* <CyclesListView <IssuesView
type="cycle"
issues={cycleIssuesArray ?? []} issues={cycleIssuesArray ?? []}
openCreateIssueModal={openCreateIssueModal}
openIssuesListModal={openIssuesListModal}
removeIssueFromCycle={removeIssueFromCycle}
setPreloadedData={setPreloadedData}
userAuth={props} userAuth={props}
/> */} openIssuesListModal={openIssuesListModal}
<IssuesView issues={cycleIssuesArray ?? []} userAuth={props} /> />
</div> </div>
) : ( ) : (
<div <div

View File

@ -1,8 +1,7 @@
import { useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import useSWR from "swr"; import useSWR from "swr";
import { RectangleStackIcon } from "@heroicons/react/24/outline";
import { PlusIcon } from "@heroicons/react/20/solid";
// lib // lib
import { requiredAdmin, requiredAuth } from "lib/auth"; import { requiredAdmin, requiredAuth } from "lib/auth";
// services // services
@ -14,25 +13,20 @@ import AppLayout from "layouts/app-layout";
import { IssueViewContextProvider } from "contexts/issue-view.context"; import { IssueViewContextProvider } from "contexts/issue-view.context";
// components // components
import { IssuesFilterView, IssuesView } from "components/core"; import { IssuesFilterView, IssuesView } from "components/core";
import { CreateUpdateIssueModal } from "components/issues";
// ui // ui
import { Spinner, EmptySpace, EmptySpaceItem, HeaderButton } from "components/ui"; import { Spinner, EmptySpace, EmptySpaceItem, HeaderButton } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// icons
import { RectangleStackIcon, PlusIcon } from "@heroicons/react/24/outline";
// types // types
import type { IIssue, UserAuth } from "types"; import type { UserAuth } from "types";
import type { NextPage, NextPageContext } from "next"; import type { NextPage, NextPageContext } from "next";
// fetch-keys // fetch-keys
import { PROJECT_DETAILS, PROJECT_ISSUES_LIST } from "constants/fetch-keys"; import { PROJECT_DETAILS, PROJECT_ISSUES_LIST } from "constants/fetch-keys";
const ProjectIssues: NextPage<UserAuth> = (props) => { const ProjectIssues: NextPage<UserAuth> = (props) => {
const [isOpen, setIsOpen] = useState(false); const router = useRouter();
const [selectedIssue, setSelectedIssue] = useState< const { workspaceSlug, projectId } = router.query;
(IIssue & { actionType: "edit" | "delete" }) | undefined
>(undefined);
const {
query: { workspaceSlug, projectId },
} = useRouter();
const { data: projectIssues } = useSWR( const { data: projectIssues } = useSWR(
workspaceSlug && projectId workspaceSlug && projectId
@ -50,23 +44,8 @@ const ProjectIssues: NextPage<UserAuth> = (props) => {
: null : null
); );
useEffect(() => {
if (!isOpen) {
const timer = setTimeout(() => {
setSelectedIssue(undefined);
clearTimeout(timer);
}, 500);
}
}, [isOpen]);
return ( return (
<IssueViewContextProvider> <IssueViewContextProvider>
<CreateUpdateIssueModal
isOpen={isOpen && selectedIssue?.actionType !== "delete"}
prePopulateData={{ ...selectedIssue }}
handleClose={() => setIsOpen(false)}
data={selectedIssue}
/>
<AppLayout <AppLayout
breadcrumbs={ breadcrumbs={
<Breadcrumbs> <Breadcrumbs>
@ -92,35 +71,42 @@ const ProjectIssues: NextPage<UserAuth> = (props) => {
</div> </div>
} }
> >
{!projectIssues ? ( {projectIssues ? (
projectIssues.count > 0 ? (
<IssuesView
issues={projectIssues?.results.filter((p) => p.parent === null) ?? []}
userAuth={props}
/>
) : (
<div className="grid h-full w-full place-items-center px-4 sm:px-0">
<EmptySpace
title="You don't have any issue yet."
description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done."
Icon={RectangleStackIcon}
>
<EmptySpaceItem
title="Create a new issue"
description={
<span>
Use <pre className="inline rounded bg-gray-100 px-2 py-1">C</pre> shortcut to
create a new issue
</span>
}
Icon={PlusIcon}
action={() => {
const e = new KeyboardEvent("keydown", {
key: "c",
});
document.dispatchEvent(e);
}}
/>
</EmptySpace>
</div>
)
) : (
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full items-center justify-center">
<Spinner /> <Spinner />
</div> </div>
) : projectIssues.count > 0 ? (
<IssuesView
issues={projectIssues?.results.filter((p) => p.parent === null) ?? []}
userAuth={props}
/>
) : (
<div className="grid h-full w-full place-items-center px-4 sm:px-0">
<EmptySpace
title="You don't have any issue yet."
description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done."
Icon={RectangleStackIcon}
>
<EmptySpaceItem
title="Create a new issue"
description={
<span>
Use <pre className="inline rounded bg-gray-100 px-2 py-1">C</pre> shortcut to
create a new issue
</span>
}
Icon={PlusIcon}
action={() => setIsOpen(true)}
/>
</EmptySpace>
</div>
)} )}
</AppLayout> </AppLayout>
</IssueViewContextProvider> </IssueViewContextProvider>

View File

@ -135,30 +135,6 @@ const SingleModule: React.FC<UserAuth> = (props) => {
setModuleIssuesListModal(true); setModuleIssuesListModal(true);
}; };
const removeIssueFromModule = (issueId: string) => {
if (!workspaceSlug || !projectId) return;
mutate<ModuleIssueResponse[]>(
MODULE_ISSUES(moduleId as string),
(prevData) => prevData?.filter((p) => p.id !== issueId),
false
);
modulesService
.removeIssueFromModule(
workspaceSlug as string,
projectId as string,
moduleId as string,
issueId
)
.then((res) => {
console.log(res);
})
.catch((e) => {
console.log(e);
});
};
const handleDeleteModule = () => { const handleDeleteModule = () => {
if (!moduleDetails) return; if (!moduleDetails) return;
@ -247,15 +223,12 @@ const SingleModule: React.FC<UserAuth> = (props) => {
{moduleIssuesArray ? ( {moduleIssuesArray ? (
moduleIssuesArray.length > 0 ? ( moduleIssuesArray.length > 0 ? (
<div className={`h-full ${moduleSidebar ? "mr-[24rem]" : ""} duration-300`}> <div className={`h-full ${moduleSidebar ? "mr-[24rem]" : ""} duration-300`}>
{/* <ModulesListView <IssuesView
type="module"
issues={moduleIssuesArray ?? []} issues={moduleIssuesArray ?? []}
openCreateIssueModal={openCreateIssueModal}
openIssuesListModal={openIssuesListModal}
removeIssueFromModule={removeIssueFromModule}
setPreloadedData={setPreloadedData}
userAuth={props} userAuth={props}
/> */} openIssuesListModal={openIssuesListModal}
<IssuesView issues={moduleIssuesArray ?? []} userAuth={props} /> />
</div> </div>
) : ( ) : (
<div <div