Compare commits

...

4 Commits

9 changed files with 143 additions and 43 deletions

View File

@ -0,0 +1,32 @@
import React from "react";
const ProjectCompletionChartSkeleton = () => {
return (
<div className="card h-100">
<div className="card-header d-flex align-items-start justify-content-between">
<div className="card-title mb-0 text-start">
<h5 className="mb-1 fw-bold placeholder-glow">
<span className="placeholder col-6 bg-light"></span>
</h5>
<p className="card-subtitle placeholder-glow">
<span className="placeholder col-8 bg-light"></span>
</p>
</div>
</div>
{/* Keep a fixed height so card doesn't shrink */}
<div className="card-body" >
<div className="placeholder-glow">
{Array.from({ length: 5 }).map((_, i) => (
<div
key={i}
className="placeholder col-12 mb-2 bg-light"
style={{ height: "20px", borderRadius: "4px" }}
></div>
))}
</div>
</div>
</div>
);
};
export default ProjectCompletionChartSkeleton;

View File

@ -0,0 +1,44 @@
// ProjectProgressChartSkeleton.jsx
import React from "react";
const ProjectProgressChartSkeleton = () => {
return (
<div className="card" style={{ minHeight: "400px" }}>
<div className="card-header">
<div className="d-flex flex-wrap justify-content-between align-items-start mb-2">
{/* Left: Title */}
<div className="card-title text-start">
<div className="placeholder-glow">
<span className="placeholder col-6 mb-2"></span>
<span className="placeholder col-4"></span>
</div>
</div>
</div>
{/* Row 2: Time Range Buttons */}
<div className="d-flex flex-wrap mt-2">
{Array(7)
.fill(0)
.map((_, idx) => (
<span
key={idx}
className="placeholder bg-light col-1 me-2"
style={{ height: "25px", borderRadius: "5px" }}
></span>
))}
</div>
</div>
<div className="card-body">
<div
className="placeholder-glow"
style={{ height: "250px", width: "100%" }}
>
<span className="placeholder bg-light col-12 h-100"></span>
</div>
</div>
</div>
);
};
export default ProjectProgressChartSkeleton;

View File

@ -0,0 +1,18 @@
import React from "react";
const TeamsSkeleton = () => {
return (
<div className="d-flex justify-content-around align-items-start mt-n2 flex-grow-1">
<div>
<div className="bg-light rounded" style={{ width: "80px", height: "24px", marginBottom: "5px" }}></div>
<div className="bg-light rounded" style={{ width: "60px", height: "12px" }}></div>
</div>
<div>
<div className="bg-light rounded" style={{ width: "80px", height: "24px", marginBottom: "5px" }}></div>
<div className="bg-light rounded" style={{ width: "60px", height: "12px" }}></div>
</div>
</div>
);
};
export default TeamsSkeleton;

View File

@ -99,7 +99,9 @@ const AttendanceOverview = () => {
}; };
return ( return (
<div className="bg-white p-4 rounded shadow d-flex flex-column"> <div
className="bg-white p-4 rounded shadow d-flex flex-column"
>
{/* Header */} {/* Header */}
<div className="d-flex justify-content-between align-items-center mb-3"> <div className="d-flex justify-content-between align-items-center mb-3">
<div className="card-title mb-0 text-start"> <div className="card-title mb-0 text-start">

View File

@ -1,11 +1,13 @@
import React from "react"; import React from "react";
import HorizontalBarChart from "../Charts/HorizontalBarChart"; import HorizontalBarChart from "../Charts/HorizontalBarChart";
import { useProjects } from "../../hooks/useProjects"; import { useProjects } from "../../hooks/useProjects";
import ProjectCompletionChartSkeleton from "../Charts/ProjectCompletionChartSkeleton";
const ProjectCompletionChart = () => { const ProjectCompletionChart = () => {
const { projects, loading } = useProjects(); const { projects, loading } = useProjects();
// Bar chart logic if (loading) return <ProjectCompletionChartSkeleton />;
const projectNames = projects?.map((p) => p.name) || []; const projectNames = projects?.map((p) => p.name) || [];
const projectProgress = const projectProgress =
projects?.map((p) => { projects?.map((p) => {
@ -16,14 +18,15 @@ const ProjectCompletionChart = () => {
}) || []; }) || [];
return ( return (
<div className="card h-100"> <div className="card" style={{ minHeight: "490px" }}>
<div className="card-header d-flex align-items-start justify-content-between"> <div className="card-header d-flex align-items-start justify-content-between">
<div className="card-title mb-0 text-start"> <div className="card-title mb-0 text-start">
<h5 className="mb-1 fw-bold ">Projects</h5> <h5 className="mb-1 fw-bold">Projects</h5>
<p className="card-subtitle">Projects Completion Status</p> <p className="card-subtitle">Projects Completion Status</p>
</div> </div>
</div> </div>
<div className="card-body"> {/* Keep same minHeight as skeleton to avoid shrinking */}
<div className="card-body" >
<HorizontalBarChart <HorizontalBarChart
categories={projectNames} categories={projectNames}
seriesData={projectProgress} seriesData={projectProgress}

View File

@ -3,6 +3,7 @@ import LineChart from "../Charts/LineChart";
import { useProjects } from "../../hooks/useProjects"; import { useProjects } from "../../hooks/useProjects";
import { useDashboard_Data } from "../../hooks/useDashboard_Data"; import { useDashboard_Data } from "../../hooks/useDashboard_Data";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import ProjectProgressChartSkeleton from "../Charts/ProjectProgressChartSkeleton";
const ProjectProgressChart = ({ const ProjectProgressChart = ({
ShowAllProject = true, ShowAllProject = true,
@ -85,7 +86,7 @@ const ProjectProgressChart = ({
: selectedProjectData?.name; : selectedProjectData?.name;
return ( return (
<div className="card"> <div className="card" style={{ minHeight: "490px" }}>
<div className="card-header"> <div className="card-header">
<div className="d-flex flex-wrap justify-content-between align-items-start mb-2"> <div className="d-flex flex-wrap justify-content-between align-items-start mb-2">
{/* Left: Title */} {/* Left: Title */}
@ -100,8 +101,7 @@ const ProjectProgressChart = ({
{["1D", "1W", "15D", "1M", "3M", "1Y", "5Y"].map((key) => ( {["1D", "1W", "15D", "1M", "3M", "1Y", "5Y"].map((key) => (
<button <button
key={key} key={key}
className={`border-0 bg-transparent px-2 py-1 text-sm rounded ${ className={`border-0 bg-transparent px-2 py-1 text-sm rounded ${range === key
range === key
? "border-bottom border-primary text-primary" ? "border-bottom border-primary text-primary"
: "text-muted" : "text-muted"
}`} }`}
@ -114,14 +114,17 @@ const ProjectProgressChart = ({
</div> </div>
</div> </div>
<div className="card-body"> {isLineChartLoading ? (
<ProjectProgressChartSkeleton />
) : (
<LineChart <LineChart
seriesData={lineChartSeries} seriesData={lineChartSeries}
categories={lineChartCategories} categories={lineChartCategories}
loading={isLineChartLoading} loading={isLineChartLoading}
lineChartCategoriesDates={lineChartCategoriesDates} lineChartCategoriesDates={lineChartCategoriesDates}
/> />
</div> )}
</div> </div>
); );
}; };

View File

@ -2,9 +2,10 @@ import React, { useCallback, useEffect, useState } from "react";
import { useDashboardProjectsCardData } from "../../hooks/useDashboard_Data"; import { useDashboardProjectsCardData } from "../../hooks/useDashboard_Data";
import eventBus from "../../services/eventBus"; import eventBus from "../../services/eventBus";
import GlobalRepository from "../../repositories/GlobalRepository"; import GlobalRepository from "../../repositories/GlobalRepository";
import TeamsSkeleton from "../Charts/TeamsSkeleton";
const Projects = () => { const Projects = () => {
const { projectsCardData } = useDashboardProjectsCardData(); const { projectsCardData,loading } = useDashboardProjectsCardData();
const [projectData, setProjectsData] = useState(projectsCardData); const [projectData, setProjectsData] = useState(projectsCardData);
useEffect(() => { useEffect(() => {
@ -37,6 +38,9 @@ const Projects = () => {
Projects Projects
</h5> </h5>
</div> </div>
{loading ? (
<TeamsSkeleton />
) : (
<div className="d-flex justify-content-around align-items-start mt-n2"> <div className="d-flex justify-content-around align-items-start mt-n2">
<div> <div>
<h4 className="mb-0 fw-bold"> <h4 className="mb-0 fw-bold">
@ -51,6 +55,7 @@ const Projects = () => {
<small className="text-muted">Ongoing</small> <small className="text-muted">Ongoing</small>
</div> </div>
</div> </div>
)}
</div> </div>
); );
}; };

View File

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import { useDashboardTasksCardData } from "../../hooks/useDashboard_Data"; import { useDashboardTasksCardData } from "../../hooks/useDashboard_Data";
import TeamsSkeleton from "../Charts/TeamsSkeleton";
const TasksCard = () => { const TasksCard = () => {
const projectId = useSelector((store) => store.localVariables?.projectId); const projectId = useSelector((store) => store.localVariables?.projectId);
const { tasksCardData, loading, error } = useDashboardTasksCardData(projectId); const { tasksCardData, loading, error } = useDashboardTasksCardData(projectId);
@ -16,11 +16,7 @@ const TasksCard = () => {
{loading ? ( {loading ? (
// Loader will be displayed when loading is true // Loader will be displayed when loading is true
<div className="d-flex justify-content-center align-items-center flex-grow-1"> <TeamsSkeleton/>
<div className="spinner-border text-primary" role="status">
<span className="visually-hidden">Loading...</span>
</div>
</div>
) : error ? ( ) : error ? (
// Error message if there's an error // Error message if there's an error
<div className="text-danger flex-grow-1 d-flex justify-content-center align-items-center">{error}</div> <div className="text-danger flex-grow-1 d-flex justify-content-center align-items-center">{error}</div>

View File

@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useState } from "react";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import { useDashboardTeamsCardData } from "../../hooks/useDashboard_Data"; import { useDashboardTeamsCardData } from "../../hooks/useDashboard_Data";
import eventBus from "../../services/eventBus"; import eventBus from "../../services/eventBus";
import TeamsSkeleton from "../Charts/TeamsSkeleton";
const Teams = () => { const Teams = () => {
const projectId = useSelector((store) => store.localVariables?.projectId); const projectId = useSelector((store) => store.localVariables?.projectId);
@ -38,11 +39,7 @@ const Teams = () => {
{loading ? ( {loading ? (
// Blue spinner loader // Blue spinner loader
<div className="d-flex justify-content-center align-items-center flex-grow-1"> <TeamsSkeleton/>
<div className="spinner-border text-primary" role="status">
<span className="visually-hidden">Loading...</span>
</div>
</div>
) : error ? ( ) : error ? (
// Error message if data fetching fails // Error message if data fetching fails
<div className="text-danger flex-grow-1 d-flex justify-content-center align-items-center">{error}</div> <div className="text-danger flex-grow-1 d-flex justify-content-center align-items-center">{error}</div>