marco.pms.web/src/components/Dashboard/ProjectProgressChart.jsx

127 lines
4.0 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState } from "react";
import LineChart from "../Charts/LineChart";
import { useProjects } from "../../hooks/useProjects";
import { useDashboard_Data } from "../../hooks/useDashboard_Data";
const ProjectProgressChart = () => {
const { projects } = useProjects();
const [selectedProjectId, setSelectedProjectId] = useState("all");
const [range, setRange] = useState("1W");
const getDaysFromRange = (range) => {
switch (range) {
case "1D": return 1;
case "1W": return 7;
case "15D": return 15;
case "1M": return 30;
case "3M": return 90;
case "1Y": return 365;
case "5Y": return 1825;
default: return 7;
}
};
const days = getDaysFromRange(range);
const today = new Date();
const FromDate = today.toLocaleDateString('en-CA');
const { dashboard_data, loading: isLineChartLoading } = useDashboard_Data({
days,
FromDate,
projectId: selectedProjectId === "all" ? null : selectedProjectId,
});
const sortedDashboardData = [...dashboard_data].sort(
(a, b) => new Date(a.date) - new Date(b.date)
);
const lineChartSeries = [
{
name: "Planned Work",
data: sortedDashboardData.map((d) => d.plannedTask || 0),
},
{
name: "Completed Work",
data: sortedDashboardData.map((d) => d.completedTask || 0),
},
];
const lineChartCategories = sortedDashboardData.map((d) =>
new Date(d.date).toLocaleDateString("en-US", { month: "short", day: "numeric" })
);
const lineChartCategoriesDates = sortedDashboardData.map((d) =>
new Date(d.date).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })
);
return (
<div className="card h-100">
<div className="card-header">
{/* Row 1: Title + Project Selector */}
<div className="d-flex flex-wrap justify-content-between align-items-center mb-2">
<div className="card-title mb-0 text-start">
<h5 className="mb-1">Project Progress</h5>
<p className="card-subtitle">Progress Overview by Project</p>
</div>
<div className="btn-group">
<button
className="btn btn-outline-primary btn-sm dropdown-toggle"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
>
{selectedProjectId === "all"
? "All Projects"
: projects?.find((p) => p.id === selectedProjectId)?.name || "Select Project"}
</button>
<ul className="dropdown-menu">
<li>
<button className="dropdown-item" onClick={() => setSelectedProjectId("all")}>
All Projects
</button>
</li>
{projects?.map((project) => (
<li key={project.id}>
<button
className="dropdown-item"
onClick={() => setSelectedProjectId(project.id)}
>
{project.name}
</button>
</li>
))}
</ul>
</div>
</div>
{/* Row 2: Time Range Buttons */}
<div className="d-flex flex-wrap  mt-2">
{["1D", "1W", "15D", "1M", "3M", "1Y", "5Y"].map((key) => (
<button
key={key}
className={`border-0 bg-transparent px-2 py-1 text-sm rounded ${
range === key ? " border-bottom border-primary text-primary" : "text-muted"
}`}
style={{ cursor: "pointer", transition: "all 0.2s ease" }}
onClick={() => setRange(key)}
>
{key}
</button>
))}
</div>
</div>
<div className="card-body ">
<LineChart
seriesData={lineChartSeries}
categories={lineChartCategories}
loading={isLineChartLoading}
lineChartCategoriesDates={lineChartCategoriesDates}
/>
</div>
</div>
);
};
export default ProjectProgressChart;