From cf2ec55d4eb2cb8f1bcaa4d383eccd9d2db5a1bc Mon Sep 17 00:00:00 2001 From: "kartik.sharma" Date: Mon, 2 Jun 2025 14:17:30 +0530 Subject: [PATCH] Creating the Weidgets in Dashboard name Pending Attendance, Attendance, Activities. --- src/components/Charts/Circle.jsx | 142 ++++++++++----------- src/components/Charts/CircleChart1.jsx | 80 ++++++++++++ src/components/Charts/Circlechart.jsx | 137 ++++++++++---------- src/components/Dashboard/Activity.jsx | 158 +++++++++++++++--------- src/components/Dashboard/Attendance.jsx | 48 ++++--- src/components/Dashboard/Dashboard.jsx | 25 +++- src/hooks/useDashboard_Data.jsx | 61 +++++++++ src/repositories/GlobalRepository.jsx | 16 ++- 8 files changed, 434 insertions(+), 233 deletions(-) create mode 100644 src/components/Charts/CircleChart1.jsx diff --git a/src/components/Charts/Circle.jsx b/src/components/Charts/Circle.jsx index 6b0669bf..da260cdb 100644 --- a/src/components/Charts/Circle.jsx +++ b/src/components/Charts/Circle.jsx @@ -2,79 +2,79 @@ import React from "react"; import ReactApexChart from "react-apexcharts"; const ApexChart = ({ completed = 0, planned = 1 }) => { -const percentage = planned > 0 ? Math.round((completed / planned) * 100) : 0; + const percentage = planned > 0 ? Math.round((completed / planned) * 100) : 0; -const options = { -chart: { -height: 200, -type: "radialBar", -toolbar: { show: false }, -}, -plotOptions: { -radialBar: { -startAngle: -135, -endAngle: 225, -hollow: { -margin: 0, -size: "60%", -background: "#fff", -dropShadow: { -enabled: true, -top: 2, -left: 0, -blur: 3, -opacity: 0.45, -}, -}, -track: { -background: "#f5f5f5", -strokeWidth: "67%", -dropShadow: { enabled: false }, -}, -dataLabels: { -show: true, -name: { -offsetY: -10, -color: "#888", -fontSize: "14px", -}, -value: { -formatter: (val) => `${val}%`, -color: "#111", -fontSize: "24px", -show: true, -}, -}, -}, -}, -fill: { -type: "gradient", -gradient: { -shade: "dark", -type: "horizontal", -shadeIntensity: 0.5, -gradientToColors: ["#ABE5A1"], -opacityFrom: 1, -opacityTo: 1, -stops: [0, 100], -}, -}, -stroke: { -lineCap: "round", -}, -labels: ["Progress"], -}; + const options = { + chart: { + height: 200, + type: "radialBar", + toolbar: { show: false }, + }, + plotOptions: { + radialBar: { + startAngle: -135, + endAngle: 225, + hollow: { + margin: 0, + size: "60%", + background: "#fff", + dropShadow: { + enabled: true, + top: 2, + left: 0, + blur: 3, + opacity: 0.45, + }, + }, + track: { + background: "#f5f5f5", + strokeWidth: "40%", + dropShadow: { enabled: false }, + }, + dataLabels: { + show: true, + name: { + offsetY: -10, + color: "#888", + fontSize: "14px", + }, + value: { + formatter: (val) => `${val}%`, + color: "#111", + fontSize: "24px", + show: true, + }, + }, + }, + }, + fill: { + type: "gradient", + gradient: { + shade: "dark", + type: "horizontal", + shadeIntensity: 0.5, + gradientToColors: ["#ABE5A1"], + opacityFrom: 1, + opacityTo: 1, + stops: [0, 100], + }, + }, + stroke: { + lineCap: "round", + }, + labels: ["Progress"], + }; -return ( -
- -
-); + return ( +
+ +
+ ); }; export default ApexChart; \ No newline at end of file diff --git a/src/components/Charts/CircleChart1.jsx b/src/components/Charts/CircleChart1.jsx new file mode 100644 index 00000000..e15a7949 --- /dev/null +++ b/src/components/Charts/CircleChart1.jsx @@ -0,0 +1,80 @@ +import React from "react"; +import ReactApexChart from "react-apexcharts"; + +const ApexChart1 = ({ Pending = 0, Assigned = 1 }) => { + const percentage = Assigned > 0 ? Math.round((Pending / Assigned) * 100) : 0; + + const options = { + chart: { + height: 200, + type: "radialBar", + toolbar: { show: false }, + }, + plotOptions: { + radialBar: { + startAngle: -135, + endAngle: 225, + hollow: { + margin: 0, + size: "60%", + background: "#fff", + dropShadow: { + enabled: true, + top: 2, + left: 0, + blur: 3, + opacity: 0.45, + }, + }, + track: { + background: "#f5f5f5", + strokeWidth: "40%", + dropShadow: { enabled: false }, + }, + dataLabels: { + show: true, + name: { + offsetY: -10, + color: "#888", + fontSize: "14px", + }, + value: { + formatter: (val) => `${val}%`, + color: "#111", + fontSize: "24px", + show: true, + }, + }, + }, + }, + fill: { + type: "gradient", + gradient: { + shade: "dark", + type: "horizontal", + shadeIntensity: 0.5, + gradientToColors: ["#ABE5A1"], + opacityFrom: 1, + opacityTo: 1, + stops: [0, 100], + }, + }, + stroke: { + lineCap: "round", + }, + labels: ["Progress"], + }; + + return ( +
+ +
+ ); +}; + +export default ApexChart1; \ No newline at end of file diff --git a/src/components/Charts/Circlechart.jsx b/src/components/Charts/Circlechart.jsx index ab1c1116..da260cdb 100644 --- a/src/components/Charts/Circlechart.jsx +++ b/src/components/Charts/Circlechart.jsx @@ -1,85 +1,80 @@ import React from "react"; import ReactApexChart from "react-apexcharts"; -const ApexChart = () => { - const [state] = React.useState({ - series: [75], // Replace this with dynamic value if needed - options: { - chart: { - height: 200, // Smaller height - type: "radialBar", - toolbar: { - show: false, // Hide toolbar - }, - }, - plotOptions: { - radialBar: { - startAngle: -135, - endAngle: 225, - hollow: { - margin: 0, - size: "60%", // Smaller inner circle - background: "#fff", - dropShadow: { - enabled: true, - top: 2, - left: 0, - blur: 3, - opacity: 0.45, - }, - }, - track: { - background: "#f5f5f5", - strokeWidth: "67%", - dropShadow: { - enabled: false, - }, - }, - dataLabels: { - show: true, - name: { - offsetY: -10, - color: "#888", - fontSize: "14px", - }, - value: { - formatter: (val) => parseInt(val), - color: "#111", - fontSize: "24px", // Smaller number - show: true, - }, - }, - }, - }, - fill: { - type: "gradient", - gradient: { - shade: "dark", - type: "horizontal", - shadeIntensity: 0.5, - gradientToColors: ["#ABE5A1"], - opacityFrom: 1, - opacityTo: 1, - stops: [0, 100], - }, - }, - stroke: { - lineCap: "round", - }, - labels: ["Percent"], +const ApexChart = ({ completed = 0, planned = 1 }) => { + const percentage = planned > 0 ? Math.round((completed / planned) * 100) : 0; + + const options = { + chart: { + height: 200, + type: "radialBar", + toolbar: { show: false }, }, - }); + plotOptions: { + radialBar: { + startAngle: -135, + endAngle: 225, + hollow: { + margin: 0, + size: "60%", + background: "#fff", + dropShadow: { + enabled: true, + top: 2, + left: 0, + blur: 3, + opacity: 0.45, + }, + }, + track: { + background: "#f5f5f5", + strokeWidth: "40%", + dropShadow: { enabled: false }, + }, + dataLabels: { + show: true, + name: { + offsetY: -10, + color: "#888", + fontSize: "14px", + }, + value: { + formatter: (val) => `${val}%`, + color: "#111", + fontSize: "24px", + show: true, + }, + }, + }, + }, + fill: { + type: "gradient", + gradient: { + shade: "dark", + type: "horizontal", + shadeIntensity: 0.5, + gradientToColors: ["#ABE5A1"], + opacityFrom: 1, + opacityTo: 1, + stops: [0, 100], + }, + }, + stroke: { + lineCap: "round", + }, + labels: ["Progress"], + }; return (
); }; -export default ApexChart; +export default ApexChart; \ No newline at end of file diff --git a/src/components/Dashboard/Activity.jsx b/src/components/Dashboard/Activity.jsx index a1f9c5fc..3ce5017e 100644 --- a/src/components/Dashboard/Activity.jsx +++ b/src/components/Dashboard/Activity.jsx @@ -3,6 +3,7 @@ import LineChart from "../Charts/LineChart"; import { useProjects } from "../../hooks/useProjects"; import { useDashboard_ActivityData } from "../../hooks/useDashboard_Data"; import ApexChart from "../Charts/Circlechart"; +import ApexChart1 from "../Charts/CircleChart1"; const LOCAL_STORAGE_PROJECT_KEY = "selectedActivityProjectId"; @@ -14,7 +15,7 @@ const Activity = () => { const initialProjectId = storedProjectId || "all"; const [selectedProjectId, setSelectedProjectId] = useState(initialProjectId); const [displayedProjectName, setDisplayedProjectName] = useState("Select Project"); - const [activeTab, setActiveTab] = useState("all"); + const [activeTab, setActiveTab] = useState("Summary"); const { dashboard_Activitydata: ActivityData, isLoading, error: isError } = useDashboard_ActivityData(selectedDate, selectedProjectId); @@ -24,7 +25,9 @@ const Activity = () => { setDisplayedProjectName("All Projects"); } else if (projects) { const foundProject = projects.find((p) => p.id === selectedProjectId); - setDisplayedProjectName(foundProject ? foundProject.name : "Select Project"); + setDisplayedProjectName( + foundProject ? foundProject.name : "Select Project" + ); } else { setDisplayedProjectName("Select Project"); } @@ -42,11 +45,11 @@ const Activity = () => { return (
-
-
+
+
Activity
-

Activity Progress Chart

+

Daily Activity Data

@@ -58,6 +61,7 @@ const Activity = () => { > {displayedProjectName} +
- {/* ✅ Date Picker Aligned Left with Padding */} -
-
- + + {/* Tabs */} +
+
    +
  • + +
  • +
  • + +
  • +
+ + {/* ✅ Date Picker Aligned Left with Padding */} + +
+
+ +
- {/* Tabs */} -
    -
  • - -
  • -
  • - -
  • -
- -
- {activeTab === "all" && ( + {/* #CircleChart for this function? */} +
+ {activeTab === "Summary" && (
-
+
{isLoading ? (

Loading activity data...

) : isError ? ( @@ -135,13 +152,17 @@ const Activity = () => { Completed / Assigned
- +
) )}
+ {/* #CircleChart1 for this function */}
{!isLoading && !isError && ActivityData && ( <> @@ -149,12 +170,15 @@ const Activity = () => { Activities

- {ActivityData.totalCompletedWork?.toLocaleString()}/ - {ActivityData.totalPlannedWork?.toLocaleString()} + {ActivityData.reportPending?.toLocaleString()}/ + {ActivityData.todaysAssigned?.toLocaleString()}

Pending / Assigned
- +
)} @@ -162,33 +186,47 @@ const Activity = () => {
)} - {activeTab === "logs" && ( -
- + {activeTab === "Details" && ( +
+
- - + + - {[{ - activity: "Code Review / Remote", - assignedToday: 3, - completed: 2 - }].map((log, index) => ( - - - + {ActivityData?.performedActivites && ActivityData.performedActivites.length > 0 ? ( + ActivityData.performedActivites.map((activity, index) => ( + + + + {/* <-- Right aligned */} + + )) + ) : ( + + - ))} + )}
Activity / LocationAssigned / CompletedLocation / ActivityAssigned / Completed
{log.activity}{log.assignedToday} / {log.completed}
+ {activity.buldingName}, {activity.floorName}, {activity.workAreaName}
+ + {activity.activityName} + + + +
{activity.assignedToday} / {activity.completedToday}
No activity data available
)} +
-
+
); }; export default Activity; + + + diff --git a/src/components/Dashboard/Attendance.jsx b/src/components/Dashboard/Attendance.jsx index 168fb065..716a9759 100644 --- a/src/components/Dashboard/Attendance.jsx +++ b/src/components/Dashboard/Attendance.jsx @@ -88,16 +88,15 @@ const Attendance = () => {
-
- {/* Tabs */} + {/* Tabs */} +
+ {/* ✅ Date Picker Aligned Left with Padding */} -
-
+
+
+
-
+
{activeTab === "Summary" && (
@@ -166,20 +173,21 @@ const Attendance = () => { {activeTab === "Details" && (
- - - + + + + {AttendanceData?.attendanceTable && - AttendanceData.attendanceTable.length > 0 ? ( + AttendanceData.attendanceTable.length > 0 ? ( AttendanceData.attendanceTable.map((record, index) => ( -
NameCheckinCheckoutNameCheckinCheckout
@@ -191,7 +199,7 @@ const Attendance = () => { minute: "2-digit", })} + {new Date(record.outTime).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", diff --git a/src/components/Dashboard/Dashboard.jsx b/src/components/Dashboard/Dashboard.jsx index b2c6b904..6d0ea072 100644 --- a/src/components/Dashboard/Dashboard.jsx +++ b/src/components/Dashboard/Dashboard.jsx @@ -3,37 +3,46 @@ import { useDashboardProjectsCardData, useDashboardTeamsCardData, useDashboardTasksCardData, + useDashboardPendingAttendenceData, } from "../../hooks/useDashboard_Data"; import Projects from "./Projects"; import Teams from "./Teams"; import TasksCard from "./Tasks"; import ProjectCompletionChart from "./ProjectCompletionChart"; import ProjectProgressChart from "./ProjectProgressChart"; -// import Attendance from "./Attendance"; +import Attendance from "./Attendance"; +import PendingAttendance from "./PendingAttendance"; +import Activity from "./Activity"; const Dashboard = () => { const { projectsCardData } = useDashboardProjectsCardData(); const { teamsCardData } = useDashboardTeamsCardData(); const { tasksCardData } = useDashboardTasksCardData(); + const { PendingAttendenceData} = useDashboardPendingAttendenceData(); return (
{/* Projects Card */} -
+
{/* Teams Card */} -
+
{/* Tasks Card */} -
+
+ {/* Pending Attendance Card */} +
+ +
+ {/* Bar Chart (Project Completion) */}
@@ -44,9 +53,13 @@ const Dashboard = () => {
- {/*
+
-
*/} +
+ +
+ +
); diff --git a/src/hooks/useDashboard_Data.jsx b/src/hooks/useDashboard_Data.jsx index a46aa0c8..2f43fa61 100644 --- a/src/hooks/useDashboard_Data.jsx +++ b/src/hooks/useDashboard_Data.jsx @@ -1,5 +1,6 @@ import { useState, useEffect } from "react"; import GlobalRepository from "../repositories/GlobalRepository"; +import Attendance from "../components/Dashboard/Attendance"; // 🔹 Dashboard Progression Data Hook export const useDashboard_Data = ({ days, FromDate, projectId }) => { @@ -67,6 +68,38 @@ export const useDashboard_AttendanceData = (date, projectId) => { return { dashboard_Attendancedata, isLineChartLoading: isLineChartLoading, error }; }; +// Activity weidget + +export const useDashboard_ActivityData = (date, projectId) => { + const [dashboard_Activitydata, setDashboard_ActivityData] = useState([]); + const [isLineChartLoading, setLoading] = useState(false); + const [error, setError] = useState(""); + + useEffect(() => { + const fetchData = async () => { + setLoading(true); + setError(""); + + try { + const response = await GlobalRepository.getDashboardActivityData(date,projectId); // date in 2nd param + setDashboard_ActivityData(response.data); + } catch (err) { + setError("Failed to fetch dashboard data."); + console.error(err); + } finally { + setLoading(false); + } + }; + + if (date && projectId !== null) { + fetchData(); + } + }, [date, projectId]); + + return { dashboard_Activitydata, isLineChartLoading: isLineChartLoading, error }; +}; + + // 🔹 Dashboard Projects Card Data Hook export const useDashboardProjectsCardData = () => { @@ -151,3 +184,31 @@ export const useDashboardTasksCardData = () => { return { tasksCardData, loading, error }; }; + +// Pending Attendance +export const useDashboardPendingAttendenceData = () => { + const [PendingAttendenceData, setPendingAttendence] = useState([]); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(""); + + useEffect(() => { + const fetchPendingAttendence = async () => { + setLoading(true); + setError(""); + + try { + const response = await GlobalRepository.getDashboardPendingAttendence(); + setPendingAttendence(response.data); + } catch (err) { + setError("Failed to fetch Pending Attendence card data."); + console.error(err); + } finally { + setLoading(false); + } + }; + + fetchPendingAttendence(); + }, []); + + return { PendingAttendenceData, loading, error }; +}; diff --git a/src/repositories/GlobalRepository.jsx b/src/repositories/GlobalRepository.jsx index eda5312e..dfb09386 100644 --- a/src/repositories/GlobalRepository.jsx +++ b/src/repositories/GlobalRepository.jsx @@ -3,12 +3,12 @@ import { api } from "../utils/axiosClient"; const GlobalRepository = { getDashboardProgressionData: ({ days = '', FromDate = '', projectId = '' }) => { let params; - if(projectId == null){ + if (projectId == null) { params = new URLSearchParams({ days: days.toString(), FromDate, }); - }else{ + } else { params = new URLSearchParams({ days: days.toString(), FromDate, @@ -19,10 +19,10 @@ const GlobalRepository = { return api.get(`/api/Dashboard/Progression?${params.toString()}`); }, - getDashboardAttendanceData: ( date,projectId ) => { + getDashboardAttendanceData: (date, projectId) => { - return api.get(`/api/Dashboard/project-attendance/${projectId}?date=${date}`); -}, + return api.get(`/api/Dashboard/project-attendance/${projectId}?date=${date}`); + }, getDashboardProjectsCardData: () => { return api.get(`/api/Dashboard/projects`); }, @@ -32,6 +32,12 @@ const GlobalRepository = { getDashboardTasksCardData: () => { return api.get(`/api/Dashboard/tasks`); }, + getDashboardPendingAttendence: () => { + return api.get(`/api/dashboard/pending-attendance`); + }, + getDashboardActivityData: ( date,projectId ) => { + return api.get(`/api/Dashboard/activities/${projectId}?date=${date}`); +}, };