forked from github/plane
87a606446f
* chore: global list layout and list item component added * chore: project view list layout consistency * chore: project view sub header consistency * chore: pages list layout consistency * chore: project view sub header improvement * chore: list layout item component improvement * chore: module list layout consistency * chore: cycle list layout consistency * chore: issue list layout consistency * chore: header height consistency * chore: sub header consistency * chore: list layout improvement * chore: inbox sidebar improvement * fix: cycle quick action * chore: inbox selected issue improvement * chore: label option removed from pages filter * chore: inbox create issue modal improvement
148 lines
5.3 KiB
TypeScript
148 lines
5.3 KiB
TypeScript
import { FC, useCallback, useRef } from "react";
|
|
import { observer } from "mobx-react";
|
|
import { useRouter } from "next/router";
|
|
import { TInboxIssueCurrentTab } from "@plane/types";
|
|
import { Loader } from "@plane/ui";
|
|
// components
|
|
import { EmptyState } from "@/components/empty-state";
|
|
import { FiltersRoot, InboxIssueAppliedFilters, InboxIssueList } from "@/components/inbox";
|
|
import { InboxSidebarLoader } from "@/components/ui";
|
|
// constants
|
|
import { EmptyStateType } from "@/constants/empty-state";
|
|
// helpers
|
|
import { cn } from "@/helpers/common.helper";
|
|
import { EInboxIssueCurrentTab } from "@/helpers/inbox.helper";
|
|
// hooks
|
|
import { useProject, useProjectInbox } from "@/hooks/store";
|
|
import { useIntersectionObserver } from "@/hooks/use-intersection-observer";
|
|
|
|
type IInboxSidebarProps = {
|
|
workspaceSlug: string;
|
|
projectId: string;
|
|
setIsMobileSidebar: (value: boolean) => void;
|
|
};
|
|
|
|
const tabNavigationOptions: { key: TInboxIssueCurrentTab; label: string }[] = [
|
|
{
|
|
key: EInboxIssueCurrentTab.OPEN,
|
|
label: "Open",
|
|
},
|
|
{
|
|
key: EInboxIssueCurrentTab.CLOSED,
|
|
label: "Closed",
|
|
},
|
|
];
|
|
|
|
export const InboxSidebar: FC<IInboxSidebarProps> = observer((props) => {
|
|
const { workspaceSlug, projectId, setIsMobileSidebar } = props;
|
|
// ref
|
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
const elementRef = useRef<HTMLDivElement>(null);
|
|
// store
|
|
const { currentProjectDetails } = useProject();
|
|
const {
|
|
currentTab,
|
|
handleCurrentTab,
|
|
loader,
|
|
inboxIssuesArray,
|
|
inboxIssuePaginationInfo,
|
|
fetchInboxPaginationIssues,
|
|
getAppliedFiltersCount,
|
|
} = useProjectInbox();
|
|
|
|
const router = useRouter();
|
|
|
|
const fetchNextPages = useCallback(() => {
|
|
if (!workspaceSlug || !projectId) return;
|
|
fetchInboxPaginationIssues(workspaceSlug.toString(), projectId.toString());
|
|
}, [workspaceSlug, projectId, fetchInboxPaginationIssues]);
|
|
// page observer
|
|
useIntersectionObserver({
|
|
containerRef,
|
|
elementRef,
|
|
callback: fetchNextPages,
|
|
rootMargin: "20%",
|
|
});
|
|
|
|
return (
|
|
<div className="bg-custom-background-100 flex-shrink-0 w-full h-full border-r border-custom-border-300 ">
|
|
<div className="relative w-full h-full flex flex-col overflow-hidden">
|
|
<div className="border-b border-custom-border-300 flex-shrink-0 w-full h-[50px] relative flex items-center gap-2 whitespace-nowrap px-3">
|
|
{tabNavigationOptions.map((option) => (
|
|
<div
|
|
key={option?.key}
|
|
className={cn(
|
|
`text-sm relative flex items-center gap-1 h-[50px] px-3 cursor-pointer transition-all font-medium`,
|
|
currentTab === option?.key ? `text-custom-primary-100` : `hover:text-custom-text-200`
|
|
)}
|
|
onClick={() => {
|
|
if (currentTab != option?.key) handleCurrentTab(option?.key);
|
|
router.push(`/${workspaceSlug}/projects/${projectId}/inbox?currentTab=${option?.key}`);
|
|
}}
|
|
>
|
|
<div>{option?.label}</div>
|
|
{option?.key === "open" && currentTab === option?.key && (
|
|
<div className="rounded-full p-1.5 py-0.5 bg-custom-primary-100/20 text-custom-primary-100 text-xs font-semibold">
|
|
{inboxIssuePaginationInfo?.total_results || 0}
|
|
</div>
|
|
)}
|
|
<div
|
|
className={cn(
|
|
`border absolute bottom-0 right-0 left-0 rounded-t-md`,
|
|
currentTab === option?.key ? `border-custom-primary-100` : `border-transparent`
|
|
)}
|
|
/>
|
|
</div>
|
|
))}
|
|
<div className="ml-auto">
|
|
<FiltersRoot />
|
|
</div>
|
|
</div>
|
|
|
|
<InboxIssueAppliedFilters />
|
|
|
|
{loader != undefined && loader === "filter-loading" && !inboxIssuePaginationInfo?.next_page_results ? (
|
|
<InboxSidebarLoader />
|
|
) : (
|
|
<div
|
|
className="w-full h-full overflow-hidden overflow-y-auto vertical-scrollbar scrollbar-md"
|
|
ref={containerRef}
|
|
>
|
|
{inboxIssuesArray.length > 0 ? (
|
|
<InboxIssueList
|
|
setIsMobileSidebar={setIsMobileSidebar}
|
|
workspaceSlug={workspaceSlug}
|
|
projectId={projectId}
|
|
projectIdentifier={currentProjectDetails?.identifier}
|
|
inboxIssues={inboxIssuesArray}
|
|
/>
|
|
) : (
|
|
<div className="flex items-center justify-center h-full w-full">
|
|
<EmptyState
|
|
type={
|
|
getAppliedFiltersCount > 0
|
|
? EmptyStateType.INBOX_SIDEBAR_FILTER_EMPTY_STATE
|
|
: currentTab === EInboxIssueCurrentTab.OPEN
|
|
? EmptyStateType.INBOX_SIDEBAR_OPEN_TAB
|
|
: EmptyStateType.INBOX_SIDEBAR_CLOSED_TAB
|
|
}
|
|
layout="screen-simple"
|
|
/>
|
|
</div>
|
|
)}
|
|
|
|
<div ref={elementRef}>
|
|
{inboxIssuePaginationInfo?.next_page_results && (
|
|
<Loader className="mx-auto w-full space-y-4 py-4 px-2">
|
|
<Loader.Item height="64px" width="w-100" />
|
|
<Loader.Item height="64px" width="w-100" />
|
|
</Loader>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
});
|