Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useTheme } from "next-themes";
import useSWR from "swr";
// plane imports
import { useTranslation } from "@plane/i18n";
import type { TIssue } from "@plane/types";
import { EIssueServiceType } from "@plane/types";
import { Loader } from "@plane/ui";
// assets
Expand All @@ -12,7 +13,6 @@ import emptyIssueLight from "@/app/assets/empty-state/search/issues-light.webp?u
// components
import { EmptyState } from "@/components/common/empty-state";
import { PageHead } from "@/components/core/page-title";
import { IssueDetailRoot } from "@/components/issues/issue-detail";
// hooks
import { useAppTheme } from "@/hooks/store/use-app-theme";
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
Expand All @@ -21,9 +21,11 @@ import { useAppRouter } from "@/hooks/use-app-router";
// plane web imports
import { useWorkItemProperties } from "@/plane-web/hooks/use-issue-properties";
import { ProjectAuthWrapper } from "@/plane-web/layouts/project-wrapper";
import { WorkItemDetailRoot } from "@/plane-web/components/browse/workItem-detail";

import type { Route } from "./+types/page";

function IssueDetailsPage({ params }: Route.ComponentProps) {
export const IssueDetailsPage = observer(function IssueDetailsPage({ params }: Route.ComponentProps) {
// router
const router = useAppRouter();
const { workspaceSlug, workItem } = params;
Expand All @@ -35,18 +37,21 @@ function IssueDetailsPage({ params }: Route.ComponentProps) {
fetchIssueWithIdentifier,
issue: { getIssueById },
} = useIssueDetail();
const { getProjectById } = useProject();
const { getProjectById, getProjectByIdentifier } = useProject();
const { toggleIssueDetailSidebar, issueDetailSidebarCollapsed } = useAppTheme();

const [projectIdentifier, sequence_id] = workItem.split("-");

// fetching issue details
const { data, isLoading, error } = useSWR(`ISSUE_DETAIL_${workspaceSlug}_${projectIdentifier}_${sequence_id}`, () =>
fetchIssueWithIdentifier(workspaceSlug.toString(), projectIdentifier, sequence_id)
const { data, isLoading, error } = useSWR<TIssue, Error>(
`ISSUE_DETAIL_${workspaceSlug}_${projectIdentifier}_${sequence_id}`,
() => fetchIssueWithIdentifier(workspaceSlug.toString(), projectIdentifier, sequence_id)
);
const issueId = data?.id;
const projectId = data?.project_id;

// derived values
const projectDetails = getProjectByIdentifier(projectIdentifier);
const issueId = data?.id;
const projectId = data?.project_id ?? projectDetails?.id ?? "";
const issue = getIssueById(issueId?.toString() || "") || undefined;
const project = (issue?.project_id && getProjectById(issue?.project_id)) || undefined;
const issueLoader = !issue || isLoading;
Expand Down Expand Up @@ -77,51 +82,56 @@ function IssueDetailsPage({ params }: Route.ComponentProps) {
if (data?.is_intake) {
router.push(`/${workspaceSlug}/projects/${data.project_id}/intake/?currentTab=open&inboxIssueId=${data?.id}`);
}
}, [workspaceSlug, data]);
}, [workspaceSlug, data, router]);

if (error && !isLoading) {
return (
<EmptyState
image={resolvedTheme === "dark" ? emptyIssueDark : emptyIssueLight}
title={t("issue.empty_state.issue_detail.title")}
description={t("issue.empty_state.issue_detail.description")}
primaryButton={{
text: t("issue.empty_state.issue_detail.primary_button.text"),
onClick: () => router.push(`/${workspaceSlug}/workspace-views/all-issues/`),
}}
/>
);
}

if (issueLoader) {
return (
<Loader className="flex h-full gap-5 p-5">
<div className="basis-2/3 space-y-2">
<Loader.Item height="30px" width="40%" />
<Loader.Item height="15px" width="60%" />
<Loader.Item height="15px" width="60%" />
<Loader.Item height="15px" width="40%" />
</div>
<div className="basis-1/3 space-y-3">
<Loader.Item height="30px" />
<Loader.Item height="30px" />
<Loader.Item height="30px" />
<Loader.Item height="30px" />
</div>
</Loader>
);
}

return (
<>
<PageHead title={pageTitle} />
{error && !issueLoader ? (
<EmptyState
image={resolvedTheme === "dark" ? emptyIssueDark : emptyIssueLight}
title={t("issue.empty_state.issue_detail.title")}
description={t("issue.empty_state.issue_detail.description")}
primaryButton={{
text: t("issue.empty_state.issue_detail.primary_button.text"),
onClick: () => router.push(`/${workspaceSlug}/workspace-views/all-issues/`),
}}
/>
) : issueLoader ? (
<Loader className="flex h-full gap-5 p-5">
<div className="basis-2/3 space-y-2">
<Loader.Item height="30px" width="40%" />
<Loader.Item height="15px" width="60%" />
<Loader.Item height="15px" width="60%" />
<Loader.Item height="15px" width="40%" />
</div>
<div className="basis-1/3 space-y-3">
<Loader.Item height="30px" />
<Loader.Item height="30px" />
<Loader.Item height="30px" />
<Loader.Item height="30px" />
</div>
</Loader>
) : (
projectId &&
issueId && (
<ProjectAuthWrapper workspaceSlug={workspaceSlug} projectId={projectId}>
<IssueDetailRoot
workspaceSlug={workspaceSlug}
projectId={projectId}
issueId={issueId}
is_archived={!!issue?.archived_at}
/>
</ProjectAuthWrapper>
)
{workspaceSlug && projectId && issueId && (
<ProjectAuthWrapper workspaceSlug={workspaceSlug} projectId={projectId}>
<WorkItemDetailRoot
workspaceSlug={workspaceSlug.toString()}
projectId={projectId.toString()}
issueId={issueId.toString()}
issue={issue}
/>
</ProjectAuthWrapper>
)}
</>
);
}
});

export default observer(IssueDetailsPage);
export default IssueDetailsPage;
23 changes: 23 additions & 0 deletions apps/web/ce/components/browse/workItem-detail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { observer } from "mobx-react";
import type { TIssue } from "@plane/types";
import { IssueDetailRoot } from "@/components/issues/issue-detail/root";

export type TWorkItemDetailRoot = {
workspaceSlug: string;
projectId: string;
issueId: string;
issue: TIssue | undefined;
};

export const WorkItemDetailRoot = observer(function WorkItemDetailRoot(props: TWorkItemDetailRoot) {
const { workspaceSlug, projectId, issueId, issue } = props;

return (
<IssueDetailRoot
workspaceSlug={workspaceSlug.toString()}
projectId={projectId.toString()}
issueId={issueId.toString()}
is_archived={!!issue?.archived_at}
/>
);
});
Loading