From c2150687a694dab37af867a52996964284cd721b Mon Sep 17 00:00:00 2001 From: guru_sainath Date: Mon, 1 Jul 2024 15:12:03 +0530 Subject: [PATCH] [WEB-1792] chore: handled loader state and empty state in notification issue peekoverview (#4985) * chore: handled loader state and empty state in notification issue peekoverview * chore: code beautyfication --- .../(projects)/notifications/page.tsx | 2 +- .../components/issues/peek-overview/error.tsx | 41 +++ .../components/issues/peek-overview/index.ts | 3 + .../issues/peek-overview/loader.tsx | 106 ++++++++ .../components/issues/peek-overview/root.tsx | 26 +- .../components/issues/peek-overview/view.tsx | 233 +++++++++--------- 6 files changed, 284 insertions(+), 127 deletions(-) create mode 100644 web/core/components/issues/peek-overview/error.tsx create mode 100644 web/core/components/issues/peek-overview/loader.tsx diff --git a/web/app/[workspaceSlug]/(projects)/notifications/page.tsx b/web/app/[workspaceSlug]/(projects)/notifications/page.tsx index 6b8a90f16..8a73d549f 100644 --- a/web/app/[workspaceSlug]/(projects)/notifications/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/notifications/page.tsx @@ -36,7 +36,7 @@ const WorkspaceDashboardPage = observer(() => { return ( <> -
+
diff --git a/web/core/components/issues/peek-overview/error.tsx b/web/core/components/issues/peek-overview/error.tsx new file mode 100644 index 000000000..a7bd98470 --- /dev/null +++ b/web/core/components/issues/peek-overview/error.tsx @@ -0,0 +1,41 @@ +"use client"; + +import { FC } from "react"; +import { MoveRight } from "lucide-react"; +import { Tooltip } from "@plane/ui"; +// components +import { EmptyState } from "@/components/common"; +// hooks +import { usePlatformOS } from "@/hooks/use-platform-os"; +// images +import emptyIssue from "@/public/empty-state/issue.svg"; + +type TIssuePeekOverviewError = { + removeRoutePeekId: () => void; +}; + +export const IssuePeekOverviewError: FC = (props) => { + const { removeRoutePeekId } = props; + // hooks + const { isMobile } = usePlatformOS(); + + return ( +
+
+ + + +
+ +
+ +
+
+ ); +}; diff --git a/web/core/components/issues/peek-overview/index.ts b/web/core/components/issues/peek-overview/index.ts index e88322880..9cd51648b 100644 --- a/web/core/components/issues/peek-overview/index.ts +++ b/web/core/components/issues/peek-overview/index.ts @@ -4,3 +4,6 @@ export * from "./issue-detail"; export * from "./properties"; export * from "./root"; export * from "./view"; + +export * from "./loader"; +export * from "./error"; diff --git a/web/core/components/issues/peek-overview/loader.tsx b/web/core/components/issues/peek-overview/loader.tsx new file mode 100644 index 000000000..99a575f45 --- /dev/null +++ b/web/core/components/issues/peek-overview/loader.tsx @@ -0,0 +1,106 @@ +"use client"; + +import { FC } from "react"; +import { MoveRight } from "lucide-react"; +import { Loader, Tooltip } from "@plane/ui"; +// hooks +import { usePlatformOS } from "@/hooks/use-platform-os"; + +type TIssuePeekOverviewLoader = { + removeRoutePeekId: () => void; +}; + +export const IssuePeekOverviewLoader: FC = (props) => { + const { removeRoutePeekId } = props; + // hooks + const { isMobile } = usePlatformOS(); + + return ( + +
+
+ + + + +
+
+ + + + +
+
+ + {/* issue title and description and comments */} +
+ + +
+ + +
+ + +
+
+ + +
+ + +
+ + +
+ + {/* sub issues */} +
+ + +
+ + {/* attachments */} +
+ +
+ + +
+
+ + {/* properties */} +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ ); +}; diff --git a/web/core/components/issues/peek-overview/root.tsx b/web/core/components/issues/peek-overview/root.tsx index 437d048e9..595685422 100644 --- a/web/core/components/issues/peek-overview/root.tsx +++ b/web/core/components/issues/peek-overview/root.tsx @@ -3,9 +3,7 @@ import { FC, useEffect, useState, useMemo } from "react"; import { observer } from "mobx-react"; import { usePathname } from "next/navigation"; -// types import { TIssue } from "@plane/types"; -// ui import { TOAST_TYPE, setPromiseToast, setToast } from "@plane/ui"; // components import { IssueView } from "@/components/issues"; @@ -60,7 +58,7 @@ export const IssuePeekOverview: FC = observer((props) => { updateIssue, removeIssue, archiveIssue, - issue: { getIssueById, fetchIssue }, + issue: { fetchIssue }, } = useIssueDetail(); const { addCycleToIssue, @@ -72,7 +70,8 @@ export const IssuePeekOverview: FC = observer((props) => { } = useIssueDetail(); const { captureIssueEvent } = useEventTracker(); // state - const [loader, setLoader] = useState(false); + const [loader, setLoader] = useState(true); + const [error, setError] = useState(false); const issueOperations: TIssuePeekOperations = useMemo( () => ({ @@ -384,27 +383,32 @@ export const IssuePeekOverview: FC = observer((props) => { useEffect(() => { if (peekIssue) { setLoader(true); - issueOperations.fetch(peekIssue.workspaceSlug, peekIssue.projectId, peekIssue.issueId).finally(() => { - setLoader(false); - }); + setError(false); + issueOperations + .fetch(peekIssue.workspaceSlug, peekIssue.projectId, peekIssue.issueId) + .catch((error) => { + console.error("Error fetching the issue", error); + setError(true); + }) + .finally(() => { + setLoader(false); + }); } }, [peekIssue, issueOperations]); if (!peekIssue?.workspaceSlug || !peekIssue?.projectId || !peekIssue?.issueId) return <>; - const issue = getIssueById(peekIssue.issueId) || undefined; - const currentProjectRole = currentWorkspaceAllProjectsRole?.[peekIssue?.projectId]; // Check if issue is editable, based on user role const isEditable = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER; - const isLoading = !issue || loader ? true : false; return ( = observer((props) => { projectId, issueId, isLoading, + isError, is_archived, disabled = false, embedIssue = false, @@ -95,8 +97,9 @@ export const IssueView: FC = observer((props) => { }; const peekOverviewIssueClassName = cn( - !embedIssue && - "fixed z-20 flex flex-col overflow-hidden rounded border border-custom-border-200 bg-custom-background-100 transition-all duration-300", + !embedIssue + ? "fixed z-20 flex flex-col overflow-hidden rounded border border-custom-border-200 bg-custom-background-100 transition-all duration-300" + : `w-full h-full`, !embedIssue && { "bottom-0 right-0 top-0 w-full md:w-[50%]": peekMode === "side-peek", "size-5/6 top-[8.33%] left-[8.33%]": peekMode === "modal", @@ -129,7 +132,7 @@ export const IssueView: FC = observer((props) => { /> )} -
+
{issueId && (
= observer((props) => { "0px 4px 8px 0px rgba(0, 0, 0, 0.12), 0px 6px 12px 0px rgba(16, 24, 40, 0.12), 0px 1px 16px 0px rgba(16, 24, 40, 0.12)", }} > - {/* header */} - setPeekMode(value)} - removeRoutePeekId={removeRoutePeekId} - toggleDeleteIssueModal={toggleDeleteIssueModal} - toggleArchiveIssueModal={toggleArchiveIssueModal} - handleRestoreIssue={handleRestore} - isArchived={is_archived} - issueId={issueId} - workspaceSlug={workspaceSlug} - projectId={projectId} - isSubmitting={isSubmitting} - disabled={disabled} - embedIssue={embedIssue} - /> - {/* content */} -
- {isLoading && !issue ? ( -
- -
- ) : ( - issue && ( - <> - {["side-peek", "modal"].includes(peekMode) ? ( -
- } + {isError && ( +
+ +
+ )} + {!isLoading && !isError && issue && ( + <> + {/* header */} + setPeekMode(value)} + removeRoutePeekId={removeRoutePeekId} + toggleDeleteIssueModal={toggleDeleteIssueModal} + toggleArchiveIssueModal={toggleArchiveIssueModal} + handleRestoreIssue={handleRestore} + isArchived={is_archived} + issueId={issueId} + workspaceSlug={workspaceSlug} + projectId={projectId} + isSubmitting={isSubmitting} + disabled={disabled} + embedIssue={embedIssue} + /> + {/* content */} +
+ {["side-peek", "modal"].includes(peekMode) ? ( +
+ setIsSubmitting(value)} + /> + + {currentUser && ( + setIsSubmitting(value)} /> + )} - {currentUser && ( - + + + + +
+ ) : ( +
+
+
+ setIsSubmitting(value)} /> - )} - + {currentUser && ( + + )} + + + +
+
+
= observer((props) => { issueOperations={issueOperations} disabled={disabled || is_archived} /> - -
- ) : ( -
-
-
- setIsSubmitting(value)} - /> - - {currentUser && ( - - )} - - - - -
-
-
- -
-
- )} - - ) - )} -
+
+ )} +
+ + )}
)}