diff --git a/src/components/Charts/Circle.jsx b/src/components/Charts/Circle.jsx new file mode 100644 index 00000000..6b0669bf --- /dev/null +++ b/src/components/Charts/Circle.jsx @@ -0,0 +1,80 @@ +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 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"], +}; + +return ( +
+ +
+); +}; + +export default ApexChart; \ No newline at end of file diff --git a/src/components/Charts/Circlechart.jsx b/src/components/Charts/Circlechart.jsx new file mode 100644 index 00000000..ab1c1116 --- /dev/null +++ b/src/components/Charts/Circlechart.jsx @@ -0,0 +1,85 @@ +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"], + }, + }); + + return ( +
+ +
+ ); +}; + +export default ApexChart; diff --git a/src/components/Dashboard/Activity.jsx b/src/components/Dashboard/Activity.jsx new file mode 100644 index 00000000..a1f9c5fc --- /dev/null +++ b/src/components/Dashboard/Activity.jsx @@ -0,0 +1,194 @@ +import React, { useState, useEffect } from "react"; +import LineChart from "../Charts/LineChart"; +import { useProjects } from "../../hooks/useProjects"; +import { useDashboard_ActivityData } from "../../hooks/useDashboard_Data"; +import ApexChart from "../Charts/Circlechart"; + +const LOCAL_STORAGE_PROJECT_KEY = "selectedActivityProjectId"; + +const Activity = () => { + const { projects } = useProjects(); + const today = new Date().toISOString().split("T")[0]; // Format: YYYY-MM-DD + const [selectedDate, setSelectedDate] = useState(today); + const storedProjectId = localStorage.getItem(LOCAL_STORAGE_PROJECT_KEY); + const initialProjectId = storedProjectId || "all"; + const [selectedProjectId, setSelectedProjectId] = useState(initialProjectId); + const [displayedProjectName, setDisplayedProjectName] = useState("Select Project"); + const [activeTab, setActiveTab] = useState("all"); + + const { dashboard_Activitydata: ActivityData, isLoading, error: isError } = + useDashboard_ActivityData(selectedDate, selectedProjectId); + + useEffect(() => { + if (selectedProjectId === "all") { + setDisplayedProjectName("All Projects"); + } else if (projects) { + const foundProject = projects.find((p) => p.id === selectedProjectId); + setDisplayedProjectName(foundProject ? foundProject.name : "Select Project"); + } else { + setDisplayedProjectName("Select Project"); + } + + localStorage.setItem(LOCAL_STORAGE_PROJECT_KEY, selectedProjectId); + }, [selectedProjectId, projects]); + + const handleProjectSelect = (projectId) => { + setSelectedProjectId(projectId); + }; + + const handleDateChange = (e) => { + setSelectedDate(e.target.value); + }; + + return ( +
+
+
+
+
Activity
+

Activity Progress Chart

+
+ +
+ +
    +
  • + +
  • + {projects?.map((project) => ( +
  • + +
  • + ))} +
+
+
+
+ + {/* ✅ Date Picker Aligned Left with Padding */} +
+
+ +
+
+ + {/* Tabs */} + + +
+ {activeTab === "all" && ( +
+
+ {isLoading ? ( +

Loading activity data...

+ ) : isError ? ( +

No data available.

+ ) : ( + ActivityData && ( + <> +
+ Allocated Task +
+

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

+ Completed / Assigned +
+ +
+ + ) + )} +
+ +
+ {!isLoading && !isError && ActivityData && ( + <> +
+ Activities +
+

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

+ Pending / Assigned +
+ +
+ + )} +
+
+ )} + + {activeTab === "logs" && ( +
+ + + + + + + + + {[{ + activity: "Code Review / Remote", + assignedToday: 3, + completed: 2 + }].map((log, index) => ( + + + + + ))} + +
Activity / LocationAssigned / Completed
{log.activity}{log.assignedToday} / {log.completed}
+
+ )} +
+
+ ); +}; + +export default Activity; diff --git a/src/components/Dashboard/Attendance.jsx b/src/components/Dashboard/Attendance.jsx new file mode 100644 index 00000000..168fb065 --- /dev/null +++ b/src/components/Dashboard/Attendance.jsx @@ -0,0 +1,218 @@ +import React, { useState, useEffect } from "react"; +import LineChart from "../Charts/LineChart"; +import { useProjects } from "../../hooks/useProjects"; +import { useDashboard_AttendanceData } from "../../hooks/useDashboard_Data"; +import ApexChart from "../Charts/Circle"; + +const LOCAL_STORAGE_PROJECT_KEY = "selectedAttendanceProjectId"; + +const Attendance = () => { + const { projects } = useProjects(); + const today = new Date().toISOString().split("T")[0]; // Format: YYYY-MM-DD + const [selectedDate, setSelectedDate] = useState(today); + const storedProjectId = localStorage.getItem(LOCAL_STORAGE_PROJECT_KEY); + const initialProjectId = storedProjectId || "all"; + const [selectedProjectId, setSelectedProjectId] = useState(initialProjectId); + const [displayedProjectName, setDisplayedProjectName] = + useState("Select Project"); + const [activeTab, setActiveTab] = useState("Summary"); + + const { + dashboard_Attendancedata: AttendanceData, + isLoading, + error: isError, + } = useDashboard_AttendanceData(selectedDate, selectedProjectId); + + useEffect(() => { + if (selectedProjectId === "all") { + setDisplayedProjectName("All Projects"); + } else if (projects) { + const foundProject = projects.find((p) => p.id === selectedProjectId); + setDisplayedProjectName( + foundProject ? foundProject.name : "Select Project" + ); + } else { + setDisplayedProjectName("Select Project"); + } + + localStorage.setItem(LOCAL_STORAGE_PROJECT_KEY, selectedProjectId); + }, [selectedProjectId, projects]); + + const handleProjectSelect = (projectId) => { + setSelectedProjectId(projectId); + }; + + const handleDateChange = (e) => { + setSelectedDate(e.target.value); + }; + + return ( +
+
+
+
+
Attendance
+

Daily Attendance Data

+
+ +
+ +
    +
  • + +
  • + {projects?.map((project) => ( +
  • + +
  • + ))} +
+
+
+
+ +
+ {/* Tabs */} +
+
    +
  • + +
  • +
  • + +
  • +
+
+ {/* ✅ Date Picker Aligned Left with Padding */} +
+
+ +
+
+
+ +
+ {activeTab === "Summary" && ( +
+
+ {isLoading ? ( +

Loading Attendance data...

+ ) : isError ? ( +

No data available.

+ ) : ( + AttendanceData && ( + <> +
+ Attendance +
+

+ {AttendanceData.checkedInEmployee?.toLocaleString()}/ + {AttendanceData.assignedEmployee?.toLocaleString()} +

+ Checked-In / Assigned +
+ +
+ + ) + )} +
+
+ )} + + {activeTab === "Details" && ( +
+ + + + + + + + + + {AttendanceData?.attendanceTable && + AttendanceData.attendanceTable.length > 0 ? ( + AttendanceData.attendanceTable.map((record, index) => ( + + + + + + )) + ) : ( + + + + )} + +
NameCheckinCheckout
+ {record.firstName} {record.lastName} + + {new Date(record.inTime).toLocaleTimeString([], { + hour: "2-digit", + minute: "2-digit", + })} + + {new Date(record.outTime).toLocaleTimeString([], { + hour: "2-digit", + minute: "2-digit", + })} +
+ No attendance data available +
+
+ )} +
+
+ ); +}; + +export default Attendance; diff --git a/src/components/Dashboard/Dashboard.jsx b/src/components/Dashboard/Dashboard.jsx index 1e4cceaf..b2c6b904 100644 --- a/src/components/Dashboard/Dashboard.jsx +++ b/src/components/Dashboard/Dashboard.jsx @@ -9,6 +9,7 @@ import Teams from "./Teams"; import TasksCard from "./Tasks"; import ProjectCompletionChart from "./ProjectCompletionChart"; import ProjectProgressChart from "./ProjectProgressChart"; +// import Attendance from "./Attendance"; const Dashboard = () => { const { projectsCardData } = useDashboardProjectsCardData(); @@ -42,6 +43,10 @@ const Dashboard = () => {
+ + {/*
+ +
*/} ); diff --git a/src/components/Dashboard/PendingAttendance.jsx b/src/components/Dashboard/PendingAttendance.jsx new file mode 100644 index 00000000..f3f1ec04 --- /dev/null +++ b/src/components/Dashboard/PendingAttendance.jsx @@ -0,0 +1,32 @@ +import React from "react"; +import { useDashboardPendingAttendenceData } from "../../hooks/useDashboard_Data"; + +const PendingAttendance = () => { + const { PendingAttendenceData } = useDashboardPendingAttendenceData(); + + return ( +
+
+
+ Pending Attendence +
+
+
+
+

+ {PendingAttendenceData.pendingCheckOut?.toLocaleString()} +

+ Checkout +
+
+

+ {PendingAttendenceData.pendingRegularization?.toLocaleString()} +

+ Regularization +
+
+
+ ); +}; + +export default PendingAttendance; \ No newline at end of file diff --git a/src/components/Project/MapUsers.jsx b/src/components/Project/MapUsers.jsx index bb429789..512b0985 100644 --- a/src/components/Project/MapUsers.jsx +++ b/src/components/Project/MapUsers.jsx @@ -14,9 +14,13 @@ const MapUsers = ({ assignedLoading, setAssignedLoading, }) => { - const { employeesList, loading: employeeLoading, error } = useAllEmployees(false); + const { + employeesList, + loading: employeeLoading, + error, + } = useAllEmployees(false); const [selectedEmployees, setSelectedEmployees] = useState([]); - const [ searchText, setSearchText ] = useState( "" ); + const [searchText, setSearchText] = useState(""); const handleAllocationData = Array.isArray(allocation) ? allocation : []; @@ -96,9 +100,8 @@ const MapUsers = ({ }); }; - const handleSubmit = () => - { - setAssignedLoading(true) + const handleSubmit = () => { + setAssignedLoading(true); const selected = selectedEmployees .filter((emp) => emp.isSelected) .map((emp) => ({ empID: emp.id, jobRoleId: emp.jobRoleId })); @@ -108,32 +111,33 @@ const MapUsers = ({ } else { showToast("Please select Employee", "error"); } - }; return ( <>
-
-
- {(filteredData.length > 0 || - allocationEmployeesData.length > 0)&& ( -
- setSearchQuery(e.target.value)} - /> -
- )} -
+
+
-
-
- Select Employee -
-
+

Assign Employee

+ +
+ {(filteredData.length > 0 || + allocationEmployeesData.length > 0) && ( +
+ setSearchQuery(e.target.value)} + /> +
+ )} + +

Select Employee

+
+
- {employeeLoading && allocationEmployeesData.length === 0 && ( -

Loading...

+ + + )} {!employeeLoading && allocationEmployeesData.length === 0 && filteredData.length === 0 && ( -

All employee assigned to Project.

+ + + )} - {!employeeLoading && allocationEmployeesData.length > 0 && filteredData.length === 0 && ( -

No matching employees found.

- )} + {!employeeLoading && + allocationEmployeesData.length > 0 && + filteredData.length === 0 && ( + + + + )} {(filteredData.length > 0 || allocationEmployeesData.length > 0) && @@ -174,14 +185,11 @@ const MapUsers = ({
{(filteredData.length > 0 || - allocationEmployeesData.length > 0) && ( - - )} + allocationEmployeesData.length > 0) && ( + + )}
Loading..
All employee assigned to Project.
No matching employees found.