diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/archived-issues/[archivedIssueId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/archived-issues/[archivedIssueId].tsx index d8238d372..046fdc0c4 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/archived-issues/[archivedIssueId].tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/archived-issues/[archivedIssueId].tsx @@ -1,43 +1,22 @@ -import { useCallback, useEffect, useState, ReactElement } from "react"; +import { useState, ReactElement } from "react"; import { useRouter } from "next/router"; -import useSWR, { mutate } from "swr"; -import { useForm } from "react-hook-form"; -// services -import { IssueService, IssueArchiveService } from "services/issue"; +import useSWR from "swr"; // hooks import useToast from "hooks/use-toast"; +import { useIssueDetail, useIssues, useProject } from "hooks/store"; // layouts import { AppLayout } from "layouts/app-layout"; // components -// FIXME: have to replace this once the issue details page is ready --issue-detail-- -// import { IssueDetailsSidebar, IssueMainContent } from "components/issues"; +import { IssueDetailRoot } from "components/issues"; import { ProjectArchivedIssueDetailsHeader } from "components/headers"; // ui import { ArchiveIcon, Loader } from "@plane/ui"; // icons import { History } from "lucide-react"; // types -import { TIssue } from "@plane/types"; import { NextPageWithLayout } from "lib/types"; -// fetch-keys -import { PROJECT_ISSUES_ACTIVITY, ISSUE_DETAILS } from "constants/fetch-keys"; -import { useProject } from "hooks/store"; - -const defaultValues: Partial = { - name: "", - // description: "", - description_html: "", - estimate_point: null, - state_id: "", - priority: "low", - target_date: new Date().toString(), - cycle_id: null, - module_id: null, -}; - -// services -const issueService = new IssueService(); -const issueArchiveService = new IssueArchiveService(); +// constants +import { EIssuesStoreType } from "constants/issue"; const ArchivedIssueDetailsPage: NextPageWithLayout = () => { // router @@ -46,84 +25,43 @@ const ArchivedIssueDetailsPage: NextPageWithLayout = () => { // states const [isRestoring, setIsRestoring] = useState(false); // hooks + const { + fetchIssue, + issue: { getIssueById }, + } = useIssueDetail(); + const { + issues: { removeIssueFromArchived }, + } = useIssues(EIssuesStoreType.ARCHIVED); const { setToastAlert } = useToast(); const { getProjectById } = useProject(); - const { data: issueDetails, mutate: mutateIssueDetails } = useSWR( - workspaceSlug && projectId && archivedIssueId ? ISSUE_DETAILS(archivedIssueId as string) : null, + const { isLoading } = useSWR( workspaceSlug && projectId && archivedIssueId - ? () => - issueArchiveService.retrieveArchivedIssue( - workspaceSlug as string, - projectId as string, - archivedIssueId as string - ) + ? `ARCHIVED_ISSUE_DETAIL_${workspaceSlug}_${projectId}_${archivedIssueId}` + : null, + workspaceSlug && projectId && archivedIssueId + ? () => fetchIssue(workspaceSlug.toString(), projectId.toString(), archivedIssueId.toString(), true) : null ); - const { reset, control, watch } = useForm({ - defaultValues, - }); - - const submitChanges = useCallback( - async (formData: Partial) => { - if (!workspaceSlug || !projectId || !archivedIssueId) return; - - mutate( - ISSUE_DETAILS(archivedIssueId as string), - (prevData) => { - if (!prevData) return prevData; - - return { - ...prevData, - ...formData, - }; - }, - false - ); - - const payload: Partial = { - ...formData, - }; - - await issueService - .patchIssue(workspaceSlug as string, projectId as string, archivedIssueId as string, payload) - .then(() => { - mutateIssueDetails(); - mutate(PROJECT_ISSUES_ACTIVITY(archivedIssueId as string)); - }) - .catch((e) => { - console.error(e); - }); - }, - [workspaceSlug, archivedIssueId, projectId, mutateIssueDetails] - ); - - useEffect(() => { - if (!issueDetails) return; - - mutate(PROJECT_ISSUES_ACTIVITY(archivedIssueId as string)); - reset({ - ...issueDetails, - }); - }, [issueDetails, reset, archivedIssueId]); + const issue = getIssueById(archivedIssueId?.toString() || "") || undefined; + if (!issue) return <>; const handleUnArchive = async () => { if (!workspaceSlug || !projectId || !archivedIssueId) return; setIsRestoring(true); - await issueArchiveService - .unarchiveIssue(workspaceSlug as string, projectId as string, archivedIssueId as string) + await removeIssueFromArchived(workspaceSlug as string, projectId as string, archivedIssueId as string) .then(() => { setToastAlert({ type: "success", title: "Success", message: - issueDetails && - `${getProjectById(issueDetails.project_id)?.identifier}-${ - issueDetails?.sequence_id - } is restored successfully under the project ${getProjectById(issueDetails.project_id)?.name}`, + issue && + `${getProjectById(issue.project_id)?.identifier}-${ + issue?.sequence_id + } is restored successfully under the project ${getProjectById(issue.project_id)?.name}`, }); router.push(`/${workspaceSlug}/projects/${projectId}/issues/${archivedIssueId}`); }) @@ -137,45 +75,11 @@ const ArchivedIssueDetailsPage: NextPageWithLayout = () => { .finally(() => setIsRestoring(false)); }; + const issueLoader = !issue || isLoading ? true : false; + return ( <> - {issueDetails && projectId ? ( -
-
- {issueDetails.archived_at && ( -
-
- -

This issue has been archived by Plane.

-
- -
- )} - {/* FIXME: have to replace this once the issue details page is ready --issue-detail-- */} - {/*
- -
*/} -
- {/* FIXME: have to replace this once the issue details page is ready --issue-detail-- */} - {/*
- -
*/} -
- ) : ( + {issueLoader ? (
@@ -190,6 +94,35 @@ const ArchivedIssueDetailsPage: NextPageWithLayout = () => {
+ ) : ( +
+
+ {issue?.archived_at && ( +
+
+ +

This issue has been archived by Plane.

+
+ +
+ )} + {workspaceSlug && projectId && archivedIssueId && ( + + )} +
+
)} ); diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx index cf28855c9..6be784368 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx @@ -59,7 +59,6 @@ const IssueDetailsPage: NextPageWithLayout = observer(() => { workspaceSlug={workspaceSlug.toString()} projectId={projectId.toString()} issueId={issueId.toString()} - is_archived={!!issue?.archived_at} /> ) )} diff --git a/web/store/issue/archived/issue.store.ts b/web/store/issue/archived/issue.store.ts index b478bf71b..a31cdfef1 100644 --- a/web/store/issue/archived/issue.store.ts +++ b/web/store/issue/archived/issue.store.ts @@ -128,8 +128,8 @@ export class ArchivedIssues extends IssueHelperStore implements IArchivedIssues try { const response = await this.archivedIssueService.unarchiveIssue(workspaceSlug, projectId, issueId); - const issueIndex = this.issues[projectId].findIndex((_issueId) => _issueId === issueId); - if (issueIndex >= 0) + const issueIndex = this.issues[projectId]?.findIndex((_issueId) => _issueId === issueId); + if (issueIndex && issueIndex >= 0) runInAction(() => { this.issues[projectId].splice(issueIndex, 1); }); diff --git a/web/store/issue/issue-details/issue.store.ts b/web/store/issue/issue-details/issue.store.ts index 284e5d201..be687eab8 100644 --- a/web/store/issue/issue-details/issue.store.ts +++ b/web/store/issue/issue-details/issue.store.ts @@ -1,13 +1,13 @@ import { makeObservable } from "mobx"; // services -import { IssueService } from "services/issue"; +import { IssueArchiveService, IssueService } from "services/issue"; // types import { IIssueDetail } from "./root.store"; import { TIssue } from "@plane/types"; export interface IIssueStoreActions { // actions - fetchIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise; + fetchIssue: (workspaceSlug: string, projectId: string, issueId: string, isArchived?: boolean) => Promise; updateIssue: (workspaceSlug: string, projectId: string, issueId: string, data: Partial) => Promise; removeIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise; addIssueToCycle: (workspaceSlug: string, projectId: string, cycleId: string, issueIds: string[]) => Promise; @@ -31,6 +31,7 @@ export class IssueStore implements IIssueStore { rootIssueDetailStore: IIssueDetail; // services issueService; + issueArchiveService; constructor(rootStore: IIssueDetail) { makeObservable(this, {}); @@ -38,6 +39,7 @@ export class IssueStore implements IIssueStore { this.rootIssueDetailStore = rootStore; // services this.issueService = new IssueService(); + this.issueArchiveService = new IssueArchiveService(); } // helper methods @@ -47,12 +49,17 @@ export class IssueStore implements IIssueStore { }; // actions - fetchIssue = async (workspaceSlug: string, projectId: string, issueId: string) => { + fetchIssue = async (workspaceSlug: string, projectId: string, issueId: string, isArchived = false) => { try { const query = { expand: "state,assignees,labels,parent", }; - const issue = (await this.issueService.retrieve(workspaceSlug, projectId, issueId, query)) as any; + + let issue: any; + + if (isArchived) issue = await this.issueArchiveService.retrieveArchivedIssue(workspaceSlug, projectId, issueId); + else issue = await this.issueService.retrieve(workspaceSlug, projectId, issueId, query); + if (!issue) throw new Error("Issue not found"); this.rootIssueDetailStore.rootIssueStore.issues.addIssue([issue]); diff --git a/web/store/issue/issue-details/root.store.ts b/web/store/issue/issue-details/root.store.ts index 141c9979a..9feb728c7 100644 --- a/web/store/issue/issue-details/root.store.ts +++ b/web/store/issue/issue-details/root.store.ts @@ -133,8 +133,8 @@ export class IssueDetail implements IIssueDetail { toggleRelationModal = (value: TIssueRelationTypes | null) => (this.isRelationModalOpen = value); // issue - fetchIssue = async (workspaceSlug: string, projectId: string, issueId: string) => - this.issue.fetchIssue(workspaceSlug, projectId, issueId); + fetchIssue = async (workspaceSlug: string, projectId: string, issueId: string, isArchived = false) => + this.issue.fetchIssue(workspaceSlug, projectId, issueId, isArchived); updateIssue = async (workspaceSlug: string, projectId: string, issueId: string, data: Partial) => this.issue.updateIssue(workspaceSlug, projectId, issueId, data); removeIssue = async (workspaceSlug: string, projectId: string, issueId: string) =>