Merge branch 'pramod_Task#185' into Issue_May_2W
This commit is contained in:
commit
b885c9a8b9
@ -1,80 +1,155 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useEmployeeAttendacesLog } from '../../hooks/useAttendance';
|
||||
import { convertShortTime } from '../../utils/dateUtils';
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useEmployeeAttendacesLog } from "../../hooks/useAttendance";
|
||||
import { convertShortTime } from "../../utils/dateUtils";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
const AttendLogs = ({ Id }) => {
|
||||
|
||||
const {logs, loading} = useEmployeeAttendacesLog( Id )
|
||||
const { logs, loading } = useEmployeeAttendacesLog(Id);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const whichActivityPerform = ( actvity ) =>
|
||||
{
|
||||
const whichActivityPerform = (actvity) => {
|
||||
switch (actvity) {
|
||||
case 1:
|
||||
return "IN"
|
||||
return (
|
||||
<i
|
||||
className="bx bx-right-arrow-circle text-success"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-offset="0,8"
|
||||
data-bs-placement="top"
|
||||
data-bs-custom-class="tooltip"
|
||||
title="Check-In"
|
||||
></i>
|
||||
);
|
||||
break;
|
||||
case 2:
|
||||
return "Requested"
|
||||
case 2:
|
||||
return (
|
||||
<i
|
||||
className="bx bx-help-circle text-secondary"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-offset="0,8"
|
||||
data-bs-placement="top"
|
||||
data-bs-custom-class="tooltip"
|
||||
title="regularize Requested"
|
||||
></i>
|
||||
);
|
||||
break;
|
||||
case 3:
|
||||
return "Deleted"
|
||||
case 3:
|
||||
return (
|
||||
<i
|
||||
className="bx bx-x-circle text-danger"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-offset="0,8"
|
||||
data-bs-placement="top"
|
||||
data-bs-custom-class="tooltip"
|
||||
title="Request Rejected"
|
||||
></i>
|
||||
);
|
||||
break;
|
||||
case 4:
|
||||
return "OUT"
|
||||
case 4:
|
||||
return (
|
||||
<i
|
||||
className="bx bx-left-arrow-circle text-danger "
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-offset="0,8"
|
||||
data-bs-placement="top"
|
||||
data-bs-custom-class="tooltip"
|
||||
title="Check-Out"
|
||||
></i>
|
||||
);
|
||||
|
||||
break;
|
||||
case 5:
|
||||
return "Regularized"
|
||||
break;
|
||||
|
||||
case 5:
|
||||
return (
|
||||
<i
|
||||
className="bx bx-check-circle text-success"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-offset="0,8"
|
||||
data-bs-placement="top"
|
||||
data-bs-custom-class="tooltip"
|
||||
title="Regularized"
|
||||
></i>
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
const LocationLink = (lat, lng) => {
|
||||
const url = `https://www.google.com/maps?q=${lat},${lng}`;
|
||||
window.open(url, "_blank"); // Open in new tab
|
||||
};
|
||||
useEffect(() => {
|
||||
const tooltipTriggerList = Array.from(
|
||||
document.querySelectorAll('[data-bs-toggle="tooltip"]')
|
||||
);
|
||||
tooltipTriggerList.forEach((el) => new bootstrap.Tooltip(el));
|
||||
}, []);
|
||||
return (
|
||||
<div className="table-responsive">
|
||||
{loading && <p>Loading..</p>}
|
||||
{ logs && logs.length > 0 && (
|
||||
<>
|
||||
<div className="d-flex justify-content-start align-items-center gap-2 my-1">
|
||||
<div className="align-item-center">
|
||||
<p className="p-0 m-0">Date : {logs[0].activityTime.slice(0,10)} </p>
|
||||
</div>
|
||||
<div className="text-start">
|
||||
{logs && !loading && (
|
||||
<p>
|
||||
Attendance for{" "}
|
||||
{logs[0]?.employee?.firstName + " " + logs[0]?.employee?.lastName}{" "}
|
||||
on {logs[0]?.activityTime.slice(0, 10)}{" "}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{loading && <p>Loading..</p>}
|
||||
{logs && logs.length > 0 && (
|
||||
<>
|
||||
<div className="d-flex justify-content-start align-items-center gap-2 my-1">
|
||||
<div className="align-item-center"></div>
|
||||
</div>
|
||||
|
||||
<table className="table table-sm mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style={{width: '15%'}}>Time</th>
|
||||
<th style={{ width: '20%' }}>Activity</th>
|
||||
<th style={{ width: '20%' }}>Date</th>
|
||||
<th style={{ width: '45%' }}>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<table className="table table-sm mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style={{ width: "20%" }}>Date</th>
|
||||
<th style={{ width: "15%" }}>Time</th>
|
||||
<th style={{ width: "20%" }}>Activity</th>
|
||||
<th style={{ width: "20%" }}>Location</th>
|
||||
<th style={{ width: "45%" }}>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{logs
|
||||
.slice()
|
||||
.sort((a, b) => b.id - a.id)
|
||||
.map((log, index) => (
|
||||
<tr key={index}>
|
||||
<td>{convertShortTime( log.activityTime )}</td>
|
||||
<td>{whichActivityPerform(log.activity)}</td>
|
||||
<td>{log.activityTime.slice(0, 10)}</td>
|
||||
<td>{convertShortTime(log.activityTime)}</td>
|
||||
<td>{whichActivityPerform(log.activity)}</td>
|
||||
<td>
|
||||
{log?.latitude != 0 ? (
|
||||
<i
|
||||
class="bx bx-location-plus text-warning cursor-pointer"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-offset="0,8"
|
||||
data-bs-placement="top"
|
||||
data-bs-custom-class="tooltip"
|
||||
title="Location"
|
||||
onClick={() =>
|
||||
LocationLink(log?.latitude, log?.longitude)
|
||||
}
|
||||
></i>
|
||||
) : (
|
||||
"--"
|
||||
)}
|
||||
</td>
|
||||
<td className="text-wrap" colSpan={3}>
|
||||
{log?.comment}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</table>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AttendLogs;
|
||||
|
||||
|
||||
|
@ -65,7 +65,8 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
|
||||
})
|
||||
);
|
||||
}
|
||||
}, [dateRange, projectId, isRefreshing]);
|
||||
}, [ dateRange, projectId, isRefreshing ] );
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -82,12 +83,13 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
|
||||
loading ? "spin":""
|
||||
}`}
|
||||
title="Refresh"
|
||||
onClick={()=>setIsRefreshing(!isRefreshing)}
|
||||
onClick={() => setIsRefreshing( !isRefreshing )}
|
||||
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="table-responsive text-nowrap">
|
||||
{data && data.length > 0 ? (
|
||||
{(data && data.length > 0 ) && (
|
||||
<table className="table mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
@ -107,14 +109,7 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
|
||||
</thead>
|
||||
<tbody>
|
||||
{loading && <td colSpan={5}>Loading...</td>}
|
||||
{error && <td colSpan={5}>{error}</td>}
|
||||
{data && data.length === 0 && (
|
||||
<tr>
|
||||
<td colSpan={5}>No Data Found</td>
|
||||
</tr>
|
||||
)}
|
||||
|
||||
{currentItems?.map((attendance, index) => (
|
||||
{currentItems?.map( ( attendance, index ) => (
|
||||
<tr key={index}>
|
||||
<td colSpan={2}>
|
||||
<div className="d-flex justify-content-start align-items-center">
|
||||
@ -133,12 +128,12 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
|
||||
</td>
|
||||
<td>
|
||||
{" "}
|
||||
{moment(attendance.checkInTime).format("DD-MMM-YYYY")}
|
||||
{moment( attendance.checkInTime ).format( "DD-MMM-YYYY" )}
|
||||
</td>
|
||||
<td>{convertShortTime(attendance.checkInTime)}</td>
|
||||
<td>{convertShortTime( attendance.checkInTime )}</td>
|
||||
<td>
|
||||
{attendance.checkOutTime
|
||||
? convertShortTime(attendance.checkOutTime)
|
||||
? convertShortTime( attendance.checkOutTime )
|
||||
: "--"}
|
||||
</td>
|
||||
<td className="text-center">
|
||||
@ -150,12 +145,14 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
) )}
|
||||
</tbody>
|
||||
</table>
|
||||
) : (
|
||||
) }
|
||||
{(!loading && data.length === 0) &&
|
||||
<span>No employee logs</span>
|
||||
)}
|
||||
}
|
||||
{error && <td colSpan={5}>{error}</td>}
|
||||
</div>
|
||||
{!loading && (
|
||||
<nav aria-label="Page ">
|
||||
@ -201,7 +198,7 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
)}
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -5,6 +5,21 @@ const EmployeeNav = ({ onPillClick, activePill }) => {
|
||||
<div className="col-md-12">
|
||||
<div className="nav-align-top ">
|
||||
<ul className="nav nav-tabs">
|
||||
|
||||
<li className="nav-item">
|
||||
<a
|
||||
className={`nav-link py-1 px-2 small ${
|
||||
activePill === "attendance" ? "active" : ""
|
||||
}`}
|
||||
href="#"
|
||||
onClick={(e) => {
|
||||
e.preventDefault(); // Prevent page reload
|
||||
onPillClick("attendance");
|
||||
}}
|
||||
>
|
||||
<i className="bx bx-group bx-sm me-1_5"></i> Attendances
|
||||
</a>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<a
|
||||
className={`nav-link py-1 px-2 small ${
|
||||
@ -19,20 +34,7 @@ const EmployeeNav = ({ onPillClick, activePill }) => {
|
||||
<i className="bx bx-user bx-sm me-1_5"></i> Documents
|
||||
</a>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<a
|
||||
className={`nav-link py-1 px-2 small ${
|
||||
activePill === "attendance" ? "active" : ""
|
||||
}`}
|
||||
href="#"
|
||||
onClick={(e) => {
|
||||
e.preventDefault(); // Prevent page reload
|
||||
onPillClick("attendance");
|
||||
}}
|
||||
>
|
||||
<i className="bx bx-group bx-sm me-1_5"></i> Attendances
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li className="nav-item">
|
||||
<a
|
||||
className={`nav-link py-1 px-2 small ${
|
||||
|
@ -38,7 +38,6 @@ const Teams = ({ project }) => {
|
||||
ProjectRepository.getProjectAllocation(project.id)
|
||||
.then((response) => {
|
||||
setEmployees(response.data);
|
||||
console.log(response.data);
|
||||
setFilteredEmployees(response.data.filter((emp) => emp.isActive));
|
||||
setEmployeeLoading(false);
|
||||
})
|
||||
|
262
src/pages/employee/AttendancesEmployeeRecords.jsx
Normal file
262
src/pages/employee/AttendancesEmployeeRecords.jsx
Normal file
@ -0,0 +1,262 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import moment from "moment";
|
||||
import DateRangePicker from "../../components/common/DateRangePicker";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { fetchEmployeeAttendanceData } from "../../slices/apiSlice/employeeAttendanceSlice";
|
||||
import usePagination from "../../hooks/usePagination";
|
||||
import Avatar from "../../components/common/Avatar";
|
||||
import { convertShortTime } from "../../utils/dateUtils";
|
||||
import RenderAttendanceStatus from "../../components/Activities/RenderAttendanceStatus";
|
||||
import AttendLogs from "../../components/Activities/AttendLogs";
|
||||
|
||||
const AttendancesEmployeeRecords = ({ employee }) => {
|
||||
const [attendances, setAttendnaces] = useState([]);
|
||||
const [selectedDate, setSelectedDate] = useState("");
|
||||
const [dateRange, setDateRange] = useState({ startDate: "", endDate: "" });
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [attendanceId, setAttendanecId] = useState();
|
||||
const dispatch = useDispatch();
|
||||
const { data, loading, error } = useSelector(
|
||||
(store) => store.employeeAttendance
|
||||
);
|
||||
|
||||
const [isRefreshing, setIsRefreshing] = useState(true);
|
||||
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
|
||||
const isSameDay = (dateStr) => {
|
||||
if (!dateStr) return false;
|
||||
const d = new Date(dateStr);
|
||||
d.setHours(0, 0, 0, 0);
|
||||
return d.getTime() === today.getTime();
|
||||
};
|
||||
|
||||
const isBeforeToday = (dateStr) => {
|
||||
if (!dateStr) return false;
|
||||
const d = new Date(dateStr);
|
||||
d.setHours(0, 0, 0, 0);
|
||||
return d.getTime() < today.getTime();
|
||||
};
|
||||
|
||||
const sortByName = (a, b) => {
|
||||
const nameA = a.firstName.toLowerCase() + a.lastName.toLowerCase();
|
||||
const nameB = b.firstName.toLowerCase() + b.lastName.toLowerCase();
|
||||
return nameA.localeCompare(nameB);
|
||||
};
|
||||
|
||||
const group1 = data
|
||||
.filter((d) => d.activity === 1 && isSameDay(d.checkInTime))
|
||||
.sort(sortByName);
|
||||
const group2 = data
|
||||
.filter((d) => d.activity === 4 && isSameDay(d.checkOutTime))
|
||||
.sort(sortByName);
|
||||
const group3 = data
|
||||
.filter((d) => d.activity === 1 && isBeforeToday(d.checkInTime))
|
||||
.sort(sortByName);
|
||||
const group4 = data
|
||||
.filter((d) => d.activity === 4 && isBeforeToday(d.checkOutTime))
|
||||
.sort(sortByName);
|
||||
const group5 = data.filter((d) => d.activity === 5).sort(sortByName);
|
||||
|
||||
const sortedFinalList = [
|
||||
...group1,
|
||||
...group2,
|
||||
...group3,
|
||||
...group4,
|
||||
...group5,
|
||||
];
|
||||
|
||||
const currentDate = new Date().toLocaleDateString("en-CA");
|
||||
const { currentPage, totalPages, currentItems, paginate } = usePagination(
|
||||
sortedFinalList,
|
||||
5
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const { startDate, endDate } = dateRange;
|
||||
if (startDate && endDate) {
|
||||
dispatch(
|
||||
fetchEmployeeAttendanceData({
|
||||
employeeId: employee,
|
||||
fromDate: startDate,
|
||||
toDate: endDate,
|
||||
})
|
||||
);
|
||||
}
|
||||
}, [dateRange, employee,isRefreshing]);
|
||||
|
||||
const openModal = (id) => {
|
||||
setAttendanecId(id);
|
||||
setIsModalOpen(true);
|
||||
};
|
||||
const closeModal = () => setIsModalOpen(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={`modal fade ${isModalOpen ? "show" : ""}`}
|
||||
tabIndex="-1"
|
||||
role="dialog"
|
||||
style={{ display: isModalOpen ? "block" : "none" }}
|
||||
aria-hidden={!isModalOpen}
|
||||
>
|
||||
{" "}
|
||||
<div
|
||||
className="modal-dialog modal-md modal-simple attendance-log-modal mx-sm-auto mx-1"
|
||||
role="document"
|
||||
>
|
||||
<div className="modal-content">
|
||||
<div className="modal-body p-sm-4 p-0">
|
||||
<button
|
||||
type="button"
|
||||
className="btn-close"
|
||||
onClick={closeModal}
|
||||
aria-label="Close"
|
||||
></button>
|
||||
|
||||
<AttendLogs Id={attendanceId} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-4 py-2 " style={{ minHeight: "500px" }}>
|
||||
<div
|
||||
className="dataTables_length text-start py-2 d-flex justify-content-between "
|
||||
id="DataTables_Table_0_length"
|
||||
>
|
||||
<div className="col-md-3 my-0 ">
|
||||
<DateRangePicker onRangeChange={setDateRange} />
|
||||
</div>
|
||||
<div className="col-md-2 m-0 text-end">
|
||||
<i
|
||||
className={`bx bx-refresh cursor-pointer fs-4 ${
|
||||
loading ? "spin" : ""
|
||||
}`}
|
||||
data-toggle="tooltip"
|
||||
title="Refresh"
|
||||
onClick={() => setIsRefreshing(!isRefreshing)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="table-responsive text-nowrap">
|
||||
{(!loading && data.length === 0) &&
|
||||
<span>No employee logs</span>
|
||||
}
|
||||
{error && <div className="text-center">{error }</div>}
|
||||
{(loading && !data ) && <div className="text-center">Loading...</div>}
|
||||
{(data && data.length > 0 ) && (
|
||||
<table className="table mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="border-top-1" colSpan={2}>
|
||||
Name
|
||||
</th>
|
||||
<th className="border-top-1">Date</th>
|
||||
<th>
|
||||
<i className="bx bxs-down-arrow-alt text-success"></i>{" "}
|
||||
Check-In
|
||||
</th>
|
||||
<th>
|
||||
<i className="bx bxs-up-arrow-alt text-danger"></i>{" "}
|
||||
Check-Out
|
||||
</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{currentItems?.map( ( attendance, index ) => (
|
||||
<tr key={index}>
|
||||
<td colSpan={2}>
|
||||
<div className="d-flex justify-content-start align-items-center">
|
||||
<Avatar
|
||||
firstName={attendance.firstName}
|
||||
lastName={attendance.lastName}
|
||||
/>
|
||||
<div className="d-flex flex-column">
|
||||
<a href="#" className="text-heading text-truncate">
|
||||
<span className="fw-normal">
|
||||
{attendance.firstName} {attendance.lastName}
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{" "}
|
||||
{moment( attendance.checkInTime ).format( "DD-MMM-YYYY" )}
|
||||
</td>
|
||||
<td>{convertShortTime( attendance.checkInTime )}</td>
|
||||
<td>
|
||||
{attendance.checkOutTime
|
||||
? convertShortTime( attendance.checkOutTime )
|
||||
: "--"}
|
||||
</td>
|
||||
|
||||
<td className="text-center">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-xs btn-secondary ms-2"
|
||||
tabIndex="0"
|
||||
aria-controls="DataTables_Table_0"
|
||||
data-bs-toggle="modal"
|
||||
onClick={() => openModal( attendance.id )}
|
||||
>
|
||||
View
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
) )}
|
||||
</tbody>
|
||||
</table>
|
||||
) }
|
||||
</div>
|
||||
{(!loading && data.length > 5) && (
|
||||
<nav aria-label="Page ">
|
||||
<ul className="pagination pagination-sm justify-content-end py-1">
|
||||
<li
|
||||
className={`page-item ${currentPage === 1 ? "disabled" : ""}`}
|
||||
>
|
||||
<button
|
||||
className="page-link btn-xs"
|
||||
onClick={() => paginate(currentPage - 1)}
|
||||
>
|
||||
«
|
||||
</button>
|
||||
</li>
|
||||
{[...Array(totalPages)].map((_, index) => (
|
||||
<li
|
||||
key={index}
|
||||
className={`page-item ${
|
||||
currentPage === index + 1 ? "active" : ""
|
||||
}`}
|
||||
>
|
||||
<button
|
||||
className="page-link "
|
||||
onClick={() => paginate(index + 1)}
|
||||
>
|
||||
{index + 1}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
<li
|
||||
className={`page-item ${
|
||||
currentPage === totalPages ? "disabled" : ""
|
||||
}`}
|
||||
>
|
||||
<button
|
||||
className="page-link "
|
||||
onClick={() => paginate(currentPage + 1)}
|
||||
>
|
||||
»
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AttendancesEmployeeRecords;
|
@ -448,7 +448,7 @@ const EmployeeList = () => {
|
||||
<div className="d-flex flex-column">
|
||||
<a
|
||||
onClick={() =>
|
||||
navigate(`/employee/${item.id}?for=account`)
|
||||
navigate(`/employee/${item.id}?for=attendance`)
|
||||
}
|
||||
className="text-heading text-truncate cursor-pointer"
|
||||
>
|
||||
|
@ -11,6 +11,7 @@ import EmployeeRepository from "../../repositories/EmployeeRepository";
|
||||
import { ComingSoonPage } from "../Misc/ComingSoonPage";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import Avatar from "../../components/common/Avatar";
|
||||
import AttendancesEmployeeRecords from "./AttendancesEmployeeRecords";
|
||||
const EmployeeProfile = () => {
|
||||
|
||||
const projectID = useSelector((store)=>store.localVariables.projectId)
|
||||
@ -54,17 +55,18 @@ const EmployeeProfile = () => {
|
||||
const renderContent = () => {
|
||||
if (loading) return <div>Loading</div>;
|
||||
switch (activePill) {
|
||||
case "account": {
|
||||
return (
|
||||
<>
|
||||
<ComingSoonPage/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
case "attendance": {
|
||||
return (
|
||||
<>
|
||||
<ComingSoonPage/>
|
||||
<AttendancesEmployeeRecords employee={employeeId } />
|
||||
|
||||
</>
|
||||
);
|
||||
}
|
||||
case "dcoument": {
|
||||
return (
|
||||
<>
|
||||
<ComingSoonPage/>
|
||||
</>
|
||||
);
|
||||
break;
|
||||
|
@ -143,7 +143,7 @@ const MasterTable = ({ data, columns, loading, handleModalData }) => {
|
||||
)}
|
||||
|
||||
{/* Pagination */}
|
||||
{!loading && (
|
||||
{!loading && safeData.length > 20 && (
|
||||
<nav aria-label="Page ">
|
||||
<ul className="pagination pagination-sm justify-content-end py-1">
|
||||
<li className={`page-item ${currentPage === 1 ? "disabled" : ""}`}>
|
||||
|
@ -19,7 +19,21 @@ const AttendanceRepository = {
|
||||
},
|
||||
|
||||
getAttendanceLogs: ( id ) => api.get( `api/attendance/log/attendance/${ id }` ),
|
||||
getRegularizeList: (id)=> api.get(`api/attendance/regularize?projectId=${id}`)
|
||||
getRegularizeList: ( id ) => api.get( `api/attendance/regularize?projectId=${ id }` ),
|
||||
|
||||
getAttendanceByEmployee: ( employeeId, fromDate, toDate ) =>
|
||||
{
|
||||
|
||||
let url = `api/Attendance/log/employee/${ employeeId }?`
|
||||
if (fromDate) {
|
||||
url += `&dateFrom=${fromDate}`;
|
||||
}
|
||||
|
||||
if (toDate) {
|
||||
url += `&dateTo=${toDate}`;
|
||||
}
|
||||
return api.get(url)
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
|
56
src/slices/apiSlice/employeeAttendanceSlice.js
Normal file
56
src/slices/apiSlice/employeeAttendanceSlice.js
Normal file
@ -0,0 +1,56 @@
|
||||
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
|
||||
import AttendanceRepository from '../../repositories/AttendanceRepository';
|
||||
import { markAttendance } from './attedanceLogsSlice';
|
||||
|
||||
export const fetchEmployeeAttendanceData = createAsyncThunk(
|
||||
'employeeAttendance/fetchEmployeeAttendanceData',
|
||||
async ( {employeeId, fromDate, toDate}, thunkAPI ) =>
|
||||
{
|
||||
try {
|
||||
const response = await AttendanceRepository.getAttendanceByEmployee( employeeId, fromDate, toDate );
|
||||
// return response?.data?.filter((log) => log.checkInTime !== null && log.activity !== 0);
|
||||
return response.data
|
||||
} catch (error) {
|
||||
return thunkAPI.rejectWithValue(error.message);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
const employeeAttendancesSlice = createSlice({
|
||||
name: 'employeeAttendance', // Updated slice name
|
||||
initialState: {
|
||||
data: [],
|
||||
loading: false,
|
||||
error: null,
|
||||
},
|
||||
reducers: {
|
||||
setEmployeeAttendanceData: (state, action) => {
|
||||
state.data = action.payload;
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder
|
||||
// Fetch attendance data
|
||||
.addCase(fetchEmployeeAttendanceData.pending, (state) => {
|
||||
state.loading = true;
|
||||
})
|
||||
.addCase(fetchEmployeeAttendanceData.fulfilled, (state, action) => {
|
||||
state.loading = false;
|
||||
state.data = action.payload;
|
||||
})
|
||||
|
||||
|
||||
.addCase(fetchEmployeeAttendanceData.rejected, (state, action) => {
|
||||
state.loading = false;
|
||||
state.error = action.payload;
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
export const { setEmployeeAttendanceData } = employeeAttendancesSlice.actions;
|
||||
export default employeeAttendancesSlice.reducer;
|
@ -3,6 +3,7 @@ import apiCacheReducer from "../slices/apiCacheSlice";
|
||||
import globalVariablesReducer from "../slices/globalVariablesSlice";
|
||||
import localVariableRducer from "../slices/localVariablesSlice"
|
||||
import attendanceReducer from "../slices/apiSlice/attedanceLogsSlice"
|
||||
import employeeAttendanceReducer from "../slices/apiSlice/employeeAttendanceSlice"
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
@ -10,5 +11,6 @@ export const store = configureStore({
|
||||
globalVariables: globalVariablesReducer,
|
||||
localVariables:localVariableRducer,
|
||||
attendanceLogs: attendanceReducer,
|
||||
employeeAttendance: employeeAttendanceReducer,
|
||||
},
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user