mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
c9337d4a41
* fix: created dashboard, widgets and dashboard widget model * fix: new user home dashboard * chore: recent projects list * chore: recent collaborators * chore: priority order change * chore: payload changes * chore: collaborator's active issue count * chore: all dashboard widgets added with services and typs * chore: centered metric for pie chart * chore: widget filters * chore: created issue filter * fix: created and assigned issues payload change * chore: created issue payload change * fix: date filter change * chore: implement filters * fix: added expansion fields * fix: changed issue structure with relation * chore: new issues response * fix: project member fix * chore: updated issue_relation structure * chore: code cleanup * chore: update issues response and added empty states * fix: button text wrap * chore: update empty state messages * fix: filters * chore: update dark mode empty states * build-error: Type check in the issue relation service * fix: issues redirection * fix: project empty state * chore: project member active check * chore: project member check in state and priority * chore: remove console logs and replace harcoded values with constants * fix: code refactoring * fix: key name changed * refactor: mapping through similar components using an array * fix: build errors --------- Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com> Co-authored-by: gurusainath <gurusainath007@gmail.com>
94 lines
3.1 KiB
TypeScript
94 lines
3.1 KiB
TypeScript
import { useEffect } from "react";
|
|
import { observer } from "mobx-react-lite";
|
|
import Link from "next/link";
|
|
// hooks
|
|
import { useDashboard } from "hooks/store";
|
|
// components
|
|
import { WidgetLoader } from "components/dashboard/widgets";
|
|
// helpers
|
|
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
|
|
import { cn } from "helpers/common.helper";
|
|
// types
|
|
import { TOverviewStatsWidgetResponse } from "@plane/types";
|
|
|
|
export type WidgetProps = {
|
|
dashboardId: string;
|
|
workspaceSlug: string;
|
|
};
|
|
|
|
const WIDGET_KEY = "overview_stats";
|
|
|
|
export const OverviewStatsWidget: React.FC<WidgetProps> = observer((props) => {
|
|
const { dashboardId, workspaceSlug } = props;
|
|
// store hooks
|
|
const { fetchWidgetStats, widgetStats: allWidgetStats } = useDashboard();
|
|
// derived values
|
|
const widgetStats = allWidgetStats?.[workspaceSlug]?.[dashboardId]?.[WIDGET_KEY] as TOverviewStatsWidgetResponse;
|
|
|
|
const today = renderFormattedPayloadDate(new Date());
|
|
const STATS_LIST = [
|
|
{
|
|
key: "assigned",
|
|
title: "Issues assigned",
|
|
count: widgetStats?.assigned_issues_count,
|
|
link: `/${workspaceSlug}/workspace-views/assigned`,
|
|
},
|
|
{
|
|
key: "overdue",
|
|
title: "Issues overdue",
|
|
count: widgetStats?.pending_issues_count,
|
|
link: `/${workspaceSlug}/workspace-views/assigned/?target_date=${today};before`,
|
|
},
|
|
{
|
|
key: "created",
|
|
title: "Issues created",
|
|
count: widgetStats?.created_issues_count,
|
|
link: `/${workspaceSlug}/workspace-views/created`,
|
|
},
|
|
{
|
|
key: "completed",
|
|
title: "Issues completed",
|
|
count: widgetStats?.completed_issues_count,
|
|
link: `/${workspaceSlug}/workspace-views/assigned?state_group=completed`,
|
|
},
|
|
];
|
|
|
|
useEffect(() => {
|
|
if (!widgetStats)
|
|
fetchWidgetStats(workspaceSlug, dashboardId, {
|
|
widget_key: WIDGET_KEY,
|
|
});
|
|
}, [dashboardId, fetchWidgetStats, widgetStats, workspaceSlug]);
|
|
|
|
if (!widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
|
|
|
|
return (
|
|
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full grid grid-cols-4 p-0.5 hover:shadow-custom-shadow-4xl duration-300">
|
|
{STATS_LIST.map((stat, index) => {
|
|
const isFirst = index === 0;
|
|
const isLast = index === STATS_LIST.length - 1;
|
|
const isMiddle = !isFirst && !isLast;
|
|
|
|
return (
|
|
<div key={stat.key} className="flex relative">
|
|
{!isLast && (
|
|
<div className="absolute right-0 top-1/2 -translate-y-1/2 h-3/5 w-[0.5px] bg-custom-border-200" />
|
|
)}
|
|
<Link
|
|
href={stat.link}
|
|
className={cn(`py-4 hover:bg-custom-background-80 duration-300 rounded-[10px] w-full break-words`, {
|
|
"pl-11 pr-[4.725rem] mr-0.5": isFirst,
|
|
"px-[4.725rem] mx-0.5": isMiddle,
|
|
"px-[4.725rem] ml-0.5": isLast,
|
|
})}
|
|
>
|
|
<h5 className="font-semibold text-xl">{stat.count}</h5>
|
|
<p className="text-custom-text-300">{stat.title}</p>
|
|
</Link>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
});
|