plane/web/components/dashboard/widgets/issue-panels/issues-list.tsx

128 lines
4.3 KiB
TypeScript
Raw Normal View History

import Link from "next/link";
// hooks
import { useIssueDetail } from "hooks/store";
// components
import {
AssignedCompletedIssueListItem,
AssignedIssuesEmptyState,
AssignedOverdueIssueListItem,
AssignedUpcomingIssueListItem,
CreatedCompletedIssueListItem,
CreatedIssuesEmptyState,
CreatedOverdueIssueListItem,
CreatedUpcomingIssueListItem,
IssueListItemProps,
} from "components/dashboard/widgets";
// ui
import { Loader, getButtonStyling } from "@plane/ui";
// helpers
import { cn } from "helpers/common.helper";
import { getRedirectionFilters } from "helpers/dashboard.helper";
// types
import { TDurationFilterOptions, TIssue, TIssuesListTypes } from "@plane/types";
export type WidgetIssuesListProps = {
filter: TDurationFilterOptions | undefined;
isLoading: boolean;
issues: TIssue[];
tab: TIssuesListTypes;
totalIssues: number;
type: "assigned" | "created";
workspaceSlug: string;
};
export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
const { filter, isLoading, issues, tab, totalIssues, type, workspaceSlug } = props;
// store hooks
const { setPeekIssue } = useIssueDetail();
const handleIssuePeekOverview = (issue: TIssue) =>
setPeekIssue({ workspaceSlug, projectId: issue.project_id, issueId: issue.id });
const filterParams = getRedirectionFilters(tab);
const ISSUE_LIST_ITEM: {
[key in string]: {
[key in TIssuesListTypes]: React.FC<IssueListItemProps>;
};
} = {
assigned: {
upcoming: AssignedUpcomingIssueListItem,
overdue: AssignedOverdueIssueListItem,
completed: AssignedCompletedIssueListItem,
},
created: {
upcoming: CreatedUpcomingIssueListItem,
overdue: CreatedOverdueIssueListItem,
completed: CreatedCompletedIssueListItem,
},
};
return (
<>
<div className="h-full">
{isLoading ? (
<Loader className="mx-6 mt-2 space-y-4">
<Loader.Item height="25px" />
<Loader.Item height="25px" />
<Loader.Item height="25px" />
<Loader.Item height="25px" />
</Loader>
) : issues.length > 0 ? (
<>
<div className="mx-6 border-b-[0.5px] border-custom-border-200 grid grid-cols-6 gap-1 text-xs text-custom-text-300 pb-1">
<h6
className={cn("pl-1 flex items-center gap-1 col-span-4", {
"col-span-6": type === "assigned" && tab === "completed",
"col-span-5": type === "created" && tab === "completed",
})}
>
Issues
<span className="flex-shrink-0 bg-custom-primary-100/20 text-custom-primary-100 text-xs font-medium py-1 px-1.5 rounded-xl h-4 min-w-6 flex items-center text-center justify-center">
{totalIssues}
</span>
</h6>
{tab === "upcoming" && <h6 className="text-center">Due date</h6>}
{tab === "overdue" && <h6 className="text-center">Due by</h6>}
{type === "assigned" && tab !== "completed" && <h6 className="text-center">Blocked by</h6>}
{type === "created" && <h6 className="text-center">Assigned to</h6>}
</div>
<div className="px-4 pb-3 mt-2">
{issues.map((issue) => {
const IssueListItem = ISSUE_LIST_ITEM[type][tab];
if (!IssueListItem) return null;
return (
<IssueListItem
key={issue.id}
issueId={issue.id}
workspaceSlug={workspaceSlug}
onClick={handleIssuePeekOverview}
/>
);
})}
</div>
</>
) : (
<div className="h-full grid items-end">
{type === "assigned" && <AssignedIssuesEmptyState filter={filter ?? "this_week"} type={tab} />}
{type === "created" && <CreatedIssuesEmptyState filter={filter ?? "this_week"} type={tab} />}
</div>
)}
</div>
{issues.length > 0 && (
<Link
href={`/${workspaceSlug}/workspace-views/${type}/${filterParams}`}
className={cn(
getButtonStyling("link-primary", "sm"),
"w-min my-3 mx-auto py-1 px-2 text-xs hover:bg-custom-primary-100/20"
)}
>
View all issues
</Link>
)}
</>
);
};