diff --git a/apps/app/components/core/board-view/board-header.tsx b/apps/app/components/core/board-view/board-header.tsx index 9fe51b793..cf394ae5e 100644 --- a/apps/app/components/core/board-view/board-header.tsx +++ b/apps/app/components/core/board-view/board-header.tsx @@ -43,10 +43,13 @@ export const BoardHeader: React.FC = ({ let assignees: any; if (selectedGroup === "assignees") { - assignees = groupTitle.split(","); - assignees = assignees - .map((a: string) => members?.find((m) => m.member.id === a)?.member.first_name) - .join(", "); + assignees = groupTitle && groupTitle !== "" ? groupTitle.split(",") : []; + assignees = + assignees.length > 0 + ? assignees + .map((a: string) => members?.find((m) => m.member.id === a)?.member.first_name) + .join(", ") + : "No assignee"; } return ( diff --git a/apps/app/components/core/board-view/single-issue.tsx b/apps/app/components/core/board-view/single-issue.tsx index 5762eb0e3..010e8ff8a 100644 --- a/apps/app/components/core/board-view/single-issue.tsx +++ b/apps/app/components/core/board-view/single-issue.tsx @@ -12,10 +12,10 @@ import { DraggingStyle, NotDraggingStyle, } from "react-beautiful-dnd"; -// constants -import { TrashIcon } from "@heroicons/react/24/outline"; // services import issuesService from "services/issues.service"; +// hooks +import useToast from "hooks/use-toast"; // components import { ViewAssigneeSelect, @@ -25,11 +25,12 @@ import { } from "components/issues/view-select"; // ui import { CustomMenu } from "components/ui"; +// helpers +import { copyTextToClipboard } from "helpers/string.helper"; // types import { CycleIssueResponse, IIssue, - IssueResponse, ModuleIssueResponse, NestedKeyOf, Properties, @@ -37,8 +38,6 @@ import { } from "types"; // fetch-keys import { CYCLE_ISSUES, MODULE_ISSUES, PROJECT_ISSUES_LIST } from "constants/fetch-keys"; -import { copyTextToClipboard } from "helpers/string.helper"; -import useToast from "hooks/use-toast"; type Props = { type?: string; @@ -71,7 +70,9 @@ export const SingleBoardIssue: React.FC = ({ }) => { const router = useRouter(); const { workspaceSlug, projectId, cycleId, moduleId } = router.query; + const { setToastAlert } = useToast(); + const partialUpdateIssue = useCallback( (formData: Partial) => { if (!workspaceSlug || !projectId) return; @@ -118,15 +119,15 @@ export const SingleBoardIssue: React.FC = ({ false ); - mutate( + mutate( PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string), - (prevData) => ({ - ...(prevData as IssueResponse), - results: (prevData?.results ?? []).map((p) => { + (prevData) => + (prevData ?? []).map((p) => { if (p.id === issue.id) return { ...p, ...formData }; + return p; }), - }), + false ); diff --git a/apps/app/components/core/bulk-delete-issues-modal.tsx b/apps/app/components/core/bulk-delete-issues-modal.tsx index ac35d9516..b5556a95f 100644 --- a/apps/app/components/core/bulk-delete-issues-modal.tsx +++ b/apps/app/components/core/bulk-delete-issues-modal.tsx @@ -18,7 +18,7 @@ import { Button } from "components/ui"; import { MagnifyingGlassIcon } from "@heroicons/react/24/outline"; import { LayerDiagonalIcon } from "components/icons"; // types -import { IIssue, IssueResponse } from "types"; +import { IIssue } from "types"; // fetch keys import { PROJECT_ISSUES_LIST } from "constants/fetch-keys"; @@ -62,8 +62,8 @@ export const BulkDeleteIssuesModal: React.FC = ({ isOpen, setIsOpen }) => const filteredIssues: IIssue[] = query === "" - ? issues?.results ?? [] - : issues?.results.filter( + ? issues ?? [] + : issues?.filter( (issue) => issue.name.toLowerCase().includes(query.toLowerCase()) || `${issue.project_detail.identifier}-${issue.sequence_id}` @@ -101,17 +101,9 @@ export const BulkDeleteIssuesModal: React.FC = ({ isOpen, setIsOpen }) => message: res.message, }); - mutate( + mutate( PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string), - (prevData) => ({ - ...(prevData as IssueResponse), - count: (prevData?.results ?? []).filter( - (p) => !data.delete_issue_ids.some((id) => p.id === id) - ).length, - results: (prevData?.results ?? []).filter( - (p) => !data.delete_issue_ids.some((id) => p.id === id) - ), - }), + (prevData) => (prevData ?? []).filter((p) => !data.delete_issue_ids.includes(p.id)), false ); handleClose(); diff --git a/apps/app/components/core/existing-issues-list-modal.tsx b/apps/app/components/core/existing-issues-list-modal.tsx index 77116d874..59faff3f6 100644 --- a/apps/app/components/core/existing-issues-list-modal.tsx +++ b/apps/app/components/core/existing-issues-list-modal.tsx @@ -103,7 +103,7 @@ export const ExistingIssuesListModal: React.FC = ({ leaveFrom="opacity-100 scale-100" leaveTo="opacity-0 scale-95" > - +
= ({ false ); - mutate( + mutate( PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string), (prevData) => { if (!prevData) return prevData; - const updatedIssues = prevData.results.map((issue) => { + const updatedIssues = prevData.map((issue) => { if (issue.id === draggedItem.id) return { ...draggedItem, @@ -174,10 +174,7 @@ export const IssuesView: React.FC = ({ return issue; }); - return { - ...prevData, - results: updatedIssues, - }; + return updatedIssues; }, false ); @@ -248,12 +245,12 @@ export const IssuesView: React.FC = ({ false ); - mutate( + mutate( PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string), (prevData) => { if (!prevData) return prevData; - const updatedIssues = prevData.results.map((issue) => { + const updatedIssues = prevData.map((issue) => { if (issue.id === draggedItem.id) return { ...draggedItem, @@ -264,10 +261,7 @@ export const IssuesView: React.FC = ({ return issue; }); - return { - ...prevData, - results: updatedIssues, - }; + return updatedIssues; }, false ); diff --git a/apps/app/components/core/list-view/single-issue.tsx b/apps/app/components/core/list-view/single-issue.tsx index 9472ccd9b..b2b74a94d 100644 --- a/apps/app/components/core/list-view/single-issue.tsx +++ b/apps/app/components/core/list-view/single-issue.tsx @@ -7,6 +7,8 @@ import { mutate } from "swr"; // services import issuesService from "services/issues.service"; +// hooks +import useToast from "hooks/use-toast"; // components import { ViewAssigneeSelect, @@ -16,19 +18,12 @@ import { } from "components/issues/view-select"; // ui import { CustomMenu } from "components/ui"; -// types -import { - CycleIssueResponse, - IIssue, - IssueResponse, - ModuleIssueResponse, - Properties, - UserAuth, -} from "types"; -// fetch-keys -import { CYCLE_ISSUES, MODULE_ISSUES, PROJECT_ISSUES_LIST, STATE_LIST } from "constants/fetch-keys"; +// helpers import { copyTextToClipboard } from "helpers/string.helper"; -import useToast from "hooks/use-toast"; +// types +import { CycleIssueResponse, IIssue, ModuleIssueResponse, Properties, UserAuth } from "types"; +// fetch-keys +import { CYCLE_ISSUES, MODULE_ISSUES, PROJECT_ISSUES_LIST } from "constants/fetch-keys"; type Props = { type?: string; @@ -98,15 +93,15 @@ export const SingleListIssue: React.FC = ({ false ); - mutate( + mutate( PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string), - (prevData) => ({ - ...(prevData as IssueResponse), - results: (prevData?.results ?? []).map((p) => { + (prevData) => + (prevData ?? []).map((p) => { if (p.id === issue.id) return { ...p, ...formData }; + return p; }), - }), + false ); diff --git a/apps/app/components/core/list-view/single-list.tsx b/apps/app/components/core/list-view/single-list.tsx index 42064f786..9c3a7ac0f 100644 --- a/apps/app/components/core/list-view/single-list.tsx +++ b/apps/app/components/core/list-view/single-list.tsx @@ -55,10 +55,13 @@ export const SingleList: React.FC = ({ let assignees: any; if (selectedGroup === "assignees") { - assignees = groupTitle.split(","); - assignees = assignees - .map((a: string) => members?.find((m) => m.member.id === a)?.member.first_name) - .join(", "); + assignees = groupTitle && groupTitle !== "" ? groupTitle.split(",") : []; + assignees = + assignees.length > 0 + ? assignees + .map((a: string) => members?.find((m) => m.member.id === a)?.member.first_name) + .join(", ") + : "No assignee"; } return ( diff --git a/apps/app/components/issues/delete-issue-modal.tsx b/apps/app/components/issues/delete-issue-modal.tsx index bbc6552ba..58df96f0d 100644 --- a/apps/app/components/issues/delete-issue-modal.tsx +++ b/apps/app/components/issues/delete-issue-modal.tsx @@ -15,7 +15,7 @@ import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; // ui import { Button } from "components/ui"; // types -import type { CycleIssueResponse, IIssue, IssueResponse, ModuleIssueResponse } from "types"; +import type { CycleIssueResponse, IIssue, ModuleIssueResponse } from "types"; // fetch-keys import { CYCLE_ISSUES, PROJECT_ISSUES_LIST, MODULE_ISSUES, USER_ISSUE } from "constants/fetch-keys"; @@ -77,13 +77,9 @@ export const DeleteIssueModal: React.FC = ({ isOpen, handleClose, data }) false ); - mutate( + mutate( PROJECT_ISSUES_LIST(workspaceSlug as string, projectId), - (prevData) => ({ - ...(prevData as IssueResponse), - results: prevData?.results.filter((i) => i.id !== data.id) ?? [], - count: (prevData?.count as number) - 1, - }), + (prevData) => (prevData ?? []).filter((i) => i.id !== data.id), false ); diff --git a/apps/app/components/issues/modal.tsx b/apps/app/components/issues/modal.tsx index 535ce7902..85147af84 100644 --- a/apps/app/components/issues/modal.tsx +++ b/apps/app/components/issues/modal.tsx @@ -16,7 +16,7 @@ import useToast from "hooks/use-toast"; // components import { IssueForm } from "components/issues"; // types -import type { IIssue, IssueResponse } from "types"; +import type { IIssue } from "types"; // fetch keys import { PROJECT_ISSUES_DETAILS, @@ -91,15 +91,13 @@ export const CreateUpdateIssueModal: React.FC = ({ false ); } else - mutate( + mutate( PROJECT_ISSUES_LIST(workspaceSlug as string, activeProject ?? ""), - (prevData) => ({ - ...(prevData as IssueResponse), - results: (prevData?.results ?? []).map((issue) => { - if (issue.id === res.id) return { ...issue, sprints: cycleId }; - return issue; + (prevData) => + (prevData ?? []).map((i) => { + if (i.id === res.id) return { ...i, sprints: cycleId }; + return i; }), - }), false ); }) @@ -126,7 +124,7 @@ export const CreateUpdateIssueModal: React.FC = ({ await issuesService .createIssues(workspaceSlug as string, activeProject ?? "", payload) .then((res) => { - mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, activeProject ?? "")); + mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, activeProject ?? "")); if (payload.cycle && payload.cycle !== "") addIssueToCycle(res.id, payload.cycle); if (payload.module && payload.module !== "") addIssueToModule(res.id, payload.module); @@ -159,15 +157,13 @@ export const CreateUpdateIssueModal: React.FC = ({ if (isUpdatingSingleIssue) { mutate(PROJECT_ISSUES_DETAILS, (prevData) => ({ ...prevData, ...res }), false); } else { - mutate( + mutate( PROJECT_ISSUES_LIST(workspaceSlug as string, activeProject ?? ""), - (prevData) => ({ - ...(prevData as IssueResponse), - results: (prevData?.results ?? []).map((issue) => { - if (issue.id === res.id) return { ...issue, ...res }; - return issue; - }), - }) + (prevData) => + (prevData ?? []).map((i) => { + if (i.id === res.id) return { ...i, ...res }; + return i; + }) ); } @@ -232,7 +228,7 @@ export const CreateUpdateIssueModal: React.FC = ({ > = ({ > i.id === issue)?.id + issues?.find((i) => i.id === issue)?.id }`} > - {`${ - issues?.results.find((i) => i.id === issue)?.project_detail?.identifier - }-${issues?.results.find((i) => i.id === issue)?.sequence_id}`} + {`${issues?.find((i) => i.id === issue)?.project_detail?.identifier}-${ + issues?.find((i) => i.id === issue)?.sequence_id + }`} @@ -243,8 +243,8 @@ export const SidebarBlockedSelect: React.FC = ({ /> { - issues?.results.find((i) => i.id === issue.id) - ?.project_detail?.identifier + issues?.find((i) => i.id === issue.id)?.project_detail + ?.identifier } -{issue.sequence_id} diff --git a/apps/app/components/issues/sidebar-select/blocker.tsx b/apps/app/components/issues/sidebar-select/blocker.tsx index c67e0a8bf..3d343260c 100644 --- a/apps/app/components/issues/sidebar-select/blocker.tsx +++ b/apps/app/components/issues/sidebar-select/blocker.tsx @@ -119,14 +119,14 @@ export const SidebarBlockerSelect: React.FC = ({ > i.id === issue)?.id + issues?.find((i) => i.id === issue)?.id }`} > - {`${ - issues?.results.find((i) => i.id === issue)?.project_detail?.identifier - }-${issues?.results.find((i) => i.id === issue)?.sequence_id}`} + {`${issues?.find((i) => i.id === issue)?.project_detail?.identifier}-${ + issues?.find((i) => i.id === issue)?.sequence_id + }`} = ({ /> { - issues?.results.find((i) => i.id === issue.id) - ?.project_detail?.identifier + issues?.find((i) => i.id === issue.id)?.project_detail + ?.identifier } -{issue.sequence_id} diff --git a/apps/app/components/issues/sidebar-select/parent.tsx b/apps/app/components/issues/sidebar-select/parent.tsx index 1af86c359..f2458a53e 100644 --- a/apps/app/components/issues/sidebar-select/parent.tsx +++ b/apps/app/components/issues/sidebar-select/parent.tsx @@ -84,9 +84,9 @@ export const SidebarParentSelect: React.FC = ({ disabled={isNotAllowed} > {watch("parent") && watch("parent") !== "" - ? `${ - issues?.results.find((i) => i.id === watch("parent"))?.project_detail?.identifier - }-${issues?.results.find((i) => i.id === watch("parent"))?.sequence_id}` + ? `${issues?.find((i) => i.id === watch("parent"))?.project_detail?.identifier}-${ + issues?.find((i) => i.id === watch("parent"))?.sequence_id + }` : "Select issue"} diff --git a/apps/app/components/issues/sidebar.tsx b/apps/app/components/issues/sidebar.tsx index 22c98ebc6..c26ac10eb 100644 --- a/apps/app/components/issues/sidebar.tsx +++ b/apps/app/components/issues/sidebar.tsx @@ -222,7 +222,7 @@ export const IssueDetailsSidebar: React.FC = ({ control={control} submitChanges={submitChanges} issuesList={ - issues?.results.filter( + issues?.filter( (i) => i.id !== issueDetail?.id && i.id !== issueDetail?.parent && @@ -250,13 +250,13 @@ export const IssueDetailsSidebar: React.FC = ({ /> i.id !== issueDetail?.id) ?? []} + issuesList={issues?.filter((i) => i.id !== issueDetail?.id) ?? []} watch={watchIssue} userAuth={userAuth} /> i.id !== issueDetail?.id) ?? []} + issuesList={issues?.filter((i) => i.id !== issueDetail?.id) ?? []} watch={watchIssue} userAuth={userAuth} /> diff --git a/apps/app/components/issues/sub-issues-list.tsx b/apps/app/components/issues/sub-issues-list.tsx index 7ef258d70..4f9b1f3fc 100644 --- a/apps/app/components/issues/sub-issues-list.tsx +++ b/apps/app/components/issues/sub-issues-list.tsx @@ -19,7 +19,7 @@ import { ChevronRightIcon, PlusIcon, XMarkIcon } from "@heroicons/react/24/outli // helpers import { orderArrayBy } from "helpers/array.helper"; // types -import { IIssue, IssueResponse, UserAuth } from "types"; +import { IIssue, UserAuth } from "types"; // fetch-keys import { PROJECT_ISSUES_LIST, SUB_ISSUES } from "constants/fetch-keys"; @@ -68,7 +68,7 @@ export const SubIssuesList: FC = ({ parentIssue, userAuth }) => { let newSubIssues = [...(prevData as IIssue[])]; data.issues.forEach((issueId: string) => { - const issue = issues?.results.find((i) => i.id === issueId); + const issue = issues?.find((i) => i.id === issueId); if (issue) newSubIssues.push(issue); }); @@ -80,11 +80,10 @@ export const SubIssuesList: FC = ({ parentIssue, userAuth }) => { false ); - mutate( + mutate( PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string), - (prevData) => ({ - ...(prevData as IssueResponse), - results: (prevData?.results ?? []).map((p) => { + (prevData) => + (prevData ?? []).map((p) => { if (data.issues.includes(p.id)) return { ...p, @@ -93,7 +92,6 @@ export const SubIssuesList: FC = ({ parentIssue, userAuth }) => { return p; }), - }), false ); @@ -118,11 +116,10 @@ export const SubIssuesList: FC = ({ parentIssue, userAuth }) => { .then((res) => { mutate(SUB_ISSUES(parentIssue.id ?? "")); - mutate( + mutate( PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string), - (prevData) => ({ - ...(prevData as IssueResponse), - results: (prevData?.results ?? []).map((p) => { + (prevData) => + (prevData ?? []).map((p) => { if (p.id === res.id) return { ...p, @@ -131,7 +128,6 @@ export const SubIssuesList: FC = ({ parentIssue, userAuth }) => { return p; }), - }), false ); }) @@ -160,7 +156,7 @@ export const SubIssuesList: FC = ({ parentIssue, userAuth }) => { isOpen={subIssuesListModal} handleClose={() => setSubIssuesListModal(false)} issues={ - issues?.results.filter( + issues?.filter( (i) => (i.parent === "" || i.parent === null) && i.id !== parentIssue?.id && diff --git a/apps/app/components/project/cycles/stats-view/single-stat.tsx b/apps/app/components/project/cycles/stats-view/single-stat.tsx index ff74b714a..7673c9615 100644 --- a/apps/app/components/project/cycles/stats-view/single-stat.tsx +++ b/apps/app/components/project/cycles/stats-view/single-stat.tsx @@ -8,6 +8,8 @@ import { useRouter } from "next/router"; import useSWR from "swr"; // services import cyclesService from "services/cycles.service"; +// hooks +import useToast from "hooks/use-toast"; // ui import { Button, CustomMenu } from "components/ui"; // icons @@ -17,12 +19,11 @@ import { CyclesIcon } from "components/icons"; // helpers import { renderShortNumericDateFormat } from "helpers/date-time.helper"; import { groupBy } from "helpers/array.helper"; +import { copyTextToClipboard } from "helpers/string.helper"; // types import { CycleIssueResponse, ICycle } from "types"; // fetch-keys import { CYCLE_ISSUES } from "constants/fetch-keys"; -import { copyTextToClipboard } from "helpers/string.helper"; -import useToast from "hooks/use-toast"; type TSingleStatProps = { cycle: ICycle; diff --git a/apps/app/components/states/delete-state-modal.tsx b/apps/app/components/states/delete-state-modal.tsx index cd5dab3be..2089b457a 100644 --- a/apps/app/components/states/delete-state-modal.tsx +++ b/apps/app/components/states/delete-state-modal.tsx @@ -74,7 +74,7 @@ export const DeleteStateModal: React.FC = ({ isOpen, onClose, data }) => }); }; - const groupedIssues = groupBy(issues?.results ?? [], "state"); + const groupedIssues = groupBy(issues ?? [], "state"); useEffect(() => { if (data) setIssuesWithThisStateExist(!!groupedIssues[data.id]); diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx index 31f8ebb2d..98cd8ae19 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx @@ -118,7 +118,7 @@ const SingleCycle: React.FC = (props) => { setCycleIssuesListModal(false)} - issues={issues?.results.filter((i) => !i.issue_cycle) ?? []} + issues={issues?.filter((i) => !i.issue_cycle) ?? []} handleOnSubmit={handleAddIssuesToCycle} /> = (props) => { } right={
- p.parent === null) ?? []} - /> + p.parent === null) ?? []} /> = (props) => { } > {projectIssues ? ( - projectIssues.count > 0 ? ( + projectIssues.length > 0 ? ( p.parent === null) ?? []} + issues={projectIssues?.filter((p) => p.parent === null) ?? []} userAuth={props} /> ) : ( diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx index 948a4b84f..561bc6965 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx @@ -113,7 +113,7 @@ const SingleModule: React.FC = (props) => { setModuleIssuesListModal(false)} - issues={issues?.results.filter((i) => !i.issue_module) ?? []} + issues={issues?.filter((i) => !i.issue_module) ?? []} handleOnSubmit={handleAddIssuesToModule} /> { + async getIssues(workspaceSlug: string, projectId: string): Promise { return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/`) .then((response) => response?.data) .catch((error) => { diff --git a/apps/app/types/issues.d.ts b/apps/app/types/issues.d.ts index f979e1fc7..40153945d 100644 --- a/apps/app/types/issues.d.ts +++ b/apps/app/types/issues.d.ts @@ -1,16 +1,5 @@ import type { IState, IUser, IProject, ICycle, IModule, IUserLite } from "./"; -export interface IssueResponse { - next_cursor: string; - prev_cursor: string; - next_page_results: boolean; - prev_page_results: boolean; - count: number; - total_pages: number; - extra_stats: null; - results: IIssue[]; -} - export interface IIssueCycle { id: string; cycle_detail: ICycle;