Implemented attendance funcationality in attendance module
This commit is contained in:
parent
a03358dd14
commit
1c0be858e9
@ -7,6 +7,7 @@ import { useSelector, useDispatch } from "react-redux";
|
|||||||
import { fetchAttendanceData } from "../../slices/apiSlice/attedanceLogsSlice";
|
import { fetchAttendanceData } from "../../slices/apiSlice/attedanceLogsSlice";
|
||||||
import DateRangePicker from "../common/DateRangePicker";
|
import DateRangePicker from "../common/DateRangePicker";
|
||||||
import { getCachedData } from "../../slices/apiDataManager";
|
import { getCachedData } from "../../slices/apiDataManager";
|
||||||
|
import eventBus from "../../services/eventBus";
|
||||||
|
|
||||||
const usePagination = (data, itemsPerPage) => {
|
const usePagination = (data, itemsPerPage) => {
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
@ -69,7 +70,7 @@ const AttendanceLog = ({ handleModalData, projectId, showOnlyCheckout }) => {
|
|||||||
setIsRefreshing(false);
|
setIsRefreshing(false);
|
||||||
}, [dateRange, projectId, dispatch, isRefreshing]);
|
}, [dateRange, projectId, dispatch, isRefreshing]);
|
||||||
|
|
||||||
useEffect(() => {
|
const filtering = (data) => {
|
||||||
const filteredData = showOnlyCheckout
|
const filteredData = showOnlyCheckout
|
||||||
? data.filter((item) => item.checkOutTime === null)
|
? data.filter((item) => item.checkOutTime === null)
|
||||||
: data;
|
: data;
|
||||||
@ -108,6 +109,10 @@ const AttendanceLog = ({ handleModalData, projectId, showOnlyCheckout }) => {
|
|||||||
// Create the final sorted array
|
// Create the final sorted array
|
||||||
const finalData = sortedDates.flatMap((date) => groupedByDate[date]);
|
const finalData = sortedDates.flatMap((date) => groupedByDate[date]);
|
||||||
setProcessedData(finalData);
|
setProcessedData(finalData);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
filtering(data)
|
||||||
}, [data, showOnlyCheckout]);
|
}, [data, showOnlyCheckout]);
|
||||||
|
|
||||||
const { currentPage, totalPages, currentItems: paginatedAttendances, paginate, resetPage } = usePagination(
|
const { currentPage, totalPages, currentItems: paginatedAttendances, paginate, resetPage } = usePagination(
|
||||||
@ -120,6 +125,34 @@ const AttendanceLog = ({ handleModalData, projectId, showOnlyCheckout }) => {
|
|||||||
resetPage();
|
resetPage();
|
||||||
}, [processedData, resetPage]);
|
}, [processedData, resetPage]);
|
||||||
|
|
||||||
|
const handler = useCallback(
|
||||||
|
(msg) => {
|
||||||
|
const { startDate, endDate } = dateRange;
|
||||||
|
const checkIn = msg.response.checkInTime.substring(0, 10);
|
||||||
|
|
||||||
|
if (
|
||||||
|
projectId === msg.projectId &&
|
||||||
|
startDate <= checkIn &&
|
||||||
|
checkIn <= endDate
|
||||||
|
) {
|
||||||
|
const updatedAttendance = data.map((item) =>
|
||||||
|
item.employeeId === msg.response.employeeId
|
||||||
|
? { ...item, ...msg.response }
|
||||||
|
: item
|
||||||
|
);
|
||||||
|
|
||||||
|
filtering(updatedAttendance);
|
||||||
|
resetPage();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[projectId, dateRange, data, filtering, resetPage]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
eventBus.on("attendance_log", handler);
|
||||||
|
return () => eventBus.off("attendance_log", handler);
|
||||||
|
}, [handler]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
import Avatar from "../common/Avatar";
|
import Avatar from "../common/Avatar";
|
||||||
import { convertShortTime } from "../../utils/dateUtils";
|
import { convertShortTime } from "../../utils/dateUtils";
|
||||||
import RegularizationActions from "./RegularizationActions";
|
import RegularizationActions from "./RegularizationActions";
|
||||||
@ -6,6 +6,8 @@ import { useSelector } from "react-redux";
|
|||||||
import { useRegularizationRequests } from "../../hooks/useAttendance";
|
import { useRegularizationRequests } from "../../hooks/useAttendance";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import usePagination from "../../hooks/usePagination";
|
import usePagination from "../../hooks/usePagination";
|
||||||
|
import eventBus from "../../services/eventBus";
|
||||||
|
import { cacheData, clearCacheKey } from "../../slices/apiDataManager";
|
||||||
|
|
||||||
const Regularization = ({ handleRequest }) => {
|
const Regularization = ({ handleRequest }) => {
|
||||||
var selectedProject = useSelector((store) => store.localVariables.projectId);
|
var selectedProject = useSelector((store) => store.localVariables.projectId);
|
||||||
@ -22,16 +24,38 @@ const Regularization = ({ handleRequest }) => {
|
|||||||
const nameB = b.firstName.toLowerCase() + b.lastName.toLowerCase();
|
const nameB = b.firstName.toLowerCase() + b.lastName.toLowerCase();
|
||||||
return nameA.localeCompare(nameB);
|
return nameA.localeCompare(nameB);
|
||||||
};
|
};
|
||||||
const filteredData = [...regularizesList]?.sort(sortByName);
|
|
||||||
|
|
||||||
|
const handler = useCallback(
|
||||||
|
(msg) => {
|
||||||
|
if (selectedProject == msg.projectId) {
|
||||||
|
const updatedAttendance = regularizes?.filter( item => item.id !== msg.response.id );
|
||||||
|
cacheData("regularizedList", {
|
||||||
|
data: updatedAttendance,
|
||||||
|
projectId: selectedProject,
|
||||||
|
});
|
||||||
|
// clearCacheKey("regularizedList")
|
||||||
|
refetch();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[selectedProject, regularizes]
|
||||||
|
);
|
||||||
|
|
||||||
|
const filteredData = [...regularizesList]?.sort(sortByName);
|
||||||
|
|
||||||
const { currentPage, totalPages, currentItems, paginate } = usePagination(
|
const { currentPage, totalPages, currentItems, paginate } = usePagination(
|
||||||
filteredData,
|
filteredData,
|
||||||
10
|
10
|
||||||
);
|
);
|
||||||
|
useEffect(() => {
|
||||||
|
eventBus.on("regularization", handler);
|
||||||
|
return () => eventBus.off("regularization", handler);
|
||||||
|
}, [handler]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="table-responsive text-nowrap" style={{minHeight:"300px"}}>
|
<div
|
||||||
|
className="table-responsive text-nowrap"
|
||||||
|
style={{ minHeight: "300px" }}
|
||||||
|
>
|
||||||
<table className="table mb-0">
|
<table className="table mb-0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@ -47,7 +71,11 @@ const Regularization = ({ handleRequest }) => {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{loading && <td colSpan={6} className="text-center py-5">Loading...</td>}
|
{loading && (
|
||||||
|
<td colSpan={6} className="text-center py-5">
|
||||||
|
Loading...
|
||||||
|
</td>
|
||||||
|
)}
|
||||||
|
|
||||||
{!loading &&
|
{!loading &&
|
||||||
(regularizes?.length > 0 ? (
|
(regularizes?.length > 0 ? (
|
||||||
@ -88,12 +116,17 @@ const Regularization = ({ handleRequest }) => {
|
|||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan={6}
|
<td
|
||||||
className="text-center" style={{
|
colSpan={6}
|
||||||
|
className="text-center"
|
||||||
|
style={{
|
||||||
height: "200px",
|
height: "200px",
|
||||||
verticalAlign: "middle",
|
verticalAlign: "middle",
|
||||||
borderBottom: "none",
|
borderBottom: "none",
|
||||||
}}>No Record Found</td>
|
}}
|
||||||
|
>
|
||||||
|
No Record Found
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -112,7 +145,8 @@ const Regularization = ({ handleRequest }) => {
|
|||||||
{[...Array(totalPages)].map((_, index) => (
|
{[...Array(totalPages)].map((_, index) => (
|
||||||
<li
|
<li
|
||||||
key={index}
|
key={index}
|
||||||
className={`page-item ${currentPage === index + 1 ? "active" : ""
|
className={`page-item ${
|
||||||
|
currentPage === index + 1 ? "active" : ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
@ -124,7 +158,8 @@ const Regularization = ({ handleRequest }) => {
|
|||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
<li
|
<li
|
||||||
className={`page-item ${currentPage === totalPages ? "disabled" : ""
|
className={`page-item ${
|
||||||
|
currentPage === totalPages ? "disabled" : ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
|
@ -1,9 +1,29 @@
|
|||||||
import React from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
import { useDashboardTeamsCardData } from "../../hooks/useDashboard_Data";
|
import { useDashboardTeamsCardData } from "../../hooks/useDashboard_Data";
|
||||||
|
import eventBus from "../../services/eventBus";
|
||||||
|
|
||||||
const Teams = () => {
|
const Teams = () => {
|
||||||
const { teamsCardData } = useDashboardTeamsCardData();
|
const { teamsCardData } = useDashboardTeamsCardData();
|
||||||
|
const[totalEmployees,setTotalEmployee] = useState(0);
|
||||||
|
const[inToday,setInToday] = useState(0);
|
||||||
|
|
||||||
|
useEffect(() =>{
|
||||||
|
setTotalEmployee(teamsCardData.totalEmployees)
|
||||||
|
setInToday(teamsCardData.inToday)
|
||||||
|
},[teamsCardData.totalEmployees,teamsCardData.inToday])
|
||||||
|
|
||||||
|
const handler = useCallback(
|
||||||
|
(msg) => {
|
||||||
|
if (msg.activity == 1) {
|
||||||
|
setInToday(prev => prev + 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[inToday]
|
||||||
|
);
|
||||||
|
useEffect(() => {
|
||||||
|
eventBus.on("attendance", handler);
|
||||||
|
return () => eventBus.off("attendance", handler);
|
||||||
|
}, [handler]);
|
||||||
return (
|
return (
|
||||||
<div className="card p-3 h-100 text-center d-flex justify-content-between">
|
<div className="card p-3 h-100 text-center d-flex justify-content-between">
|
||||||
<div className="d-flex justify-content-start align-items-center mb-3">
|
<div className="d-flex justify-content-start align-items-center mb-3">
|
||||||
@ -14,13 +34,13 @@ const Teams = () => {
|
|||||||
<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">
|
||||||
{teamsCardData.totalEmployees?.toLocaleString()}
|
{totalEmployees?.toLocaleString()}
|
||||||
</h4>
|
</h4>
|
||||||
<small className="text-muted">Total Employees</small>
|
<small className="text-muted">Total Employees</small>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h4 className="mb-0 fw-bold">
|
<h4 className="mb-0 fw-bold">
|
||||||
{teamsCardData.inToday?.toLocaleString()}
|
{inToday?.toLocaleString()}
|
||||||
</h4>
|
</h4>
|
||||||
<small className="text-muted">In Today</small>
|
<small className="text-muted">In Today</small>
|
||||||
</div>
|
</div>
|
||||||
|
@ -43,10 +43,8 @@ const AttendancePage = () => {
|
|||||||
description: "",
|
description: "",
|
||||||
date: new Date().toLocaleDateString(),
|
date: new Date().toLocaleDateString(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const handler = useCallback(
|
const handler = useCallback(
|
||||||
(msg) => {
|
(msg) => {
|
||||||
console.log("Equal:", selectedProject == msg.projectId);
|
|
||||||
if (selectedProject == msg.projectId) {
|
if (selectedProject == msg.projectId) {
|
||||||
const updatedAttendance = attendances.map((item) =>
|
const updatedAttendance = attendances.map((item) =>
|
||||||
item.employeeId === msg.response.employeeId
|
item.employeeId === msg.response.employeeId
|
||||||
|
@ -3,15 +3,14 @@ import { clearCacheKey, getCachedData } from "../slices/apiDataManager";
|
|||||||
import showToast from "./toastService";
|
import showToast from "./toastService";
|
||||||
import eventBus from "./eventBus";
|
import eventBus from "./eventBus";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
// const base_Url = process.env.VITE_BASE_URL;
|
const base_Url = process.env.VITE_BASE_URL;
|
||||||
const base_Url = "https://devapi.marcoaiot.com";
|
// const base_Url = "https://devapi.marcoaiot.com";
|
||||||
let connection = null;
|
let connection = null;
|
||||||
|
|
||||||
const targetPath = "";
|
const targetPath = "";
|
||||||
|
|
||||||
export function startSignalR(loggedUser) {
|
export function startSignalR(loggedUser) {
|
||||||
var jwtToken = localStorage.getItem("jwtToken");
|
var jwtToken = localStorage.getItem("jwtToken");
|
||||||
console.log("token", jwtToken);
|
|
||||||
connection = new signalR.HubConnectionBuilder()
|
connection = new signalR.HubConnectionBuilder()
|
||||||
.withUrl(`${base_Url}/hubs/marco`, {
|
.withUrl(`${base_Url}/hubs/marco`, {
|
||||||
accessTokenFactory: () => jwtToken,
|
accessTokenFactory: () => jwtToken,
|
||||||
@ -20,12 +19,26 @@ export function startSignalR(loggedUser) {
|
|||||||
})
|
})
|
||||||
.withAutomaticReconnect()
|
.withAutomaticReconnect()
|
||||||
.build();
|
.build();
|
||||||
|
const todayDate = new Date();
|
||||||
|
const today = new Date(
|
||||||
|
Date.UTC(todayDate.getFullYear(), todayDate.getMonth(), todayDate.getDate())
|
||||||
|
)
|
||||||
|
.toISOString()
|
||||||
|
.split("T")[0];
|
||||||
connection.on("Attendance", (data) => {
|
connection.on("Attendance", (data) => {
|
||||||
clearCacheKey("Attendance");
|
const checkIn = data.response.checkInTime.substring(0, 10);
|
||||||
if (data.loginUserId != loggedUser?.employeeInfo.id) {
|
if (data.loginUserId != loggedUser?.employeeInfo.id) {
|
||||||
|
if (today === checkIn) {
|
||||||
eventBus.emit("attendance", data);
|
eventBus.emit("attendance", data);
|
||||||
}
|
}
|
||||||
|
var onlyDate = Number(checkIn.substring(8, 10));
|
||||||
|
|
||||||
|
var afterTwoDay = checkIn.substring(0, 8) + (onlyDate + 2).toString().padStart(2, "0");;
|
||||||
|
if(afterTwoDay <= today && (data.response.activity == 4 || data.response.activity == 5)){
|
||||||
|
eventBus.emit("regularization", data);
|
||||||
|
}
|
||||||
|
eventBus.emit("attendance_log", data);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connection
|
connection
|
||||||
|
Loading…
x
Reference in New Issue
Block a user