Merge branch 'Issue_May_2W' of https://git.marcoaiot.com/admin/marco.pms.web into pramod_Task#186DeleteActivity
This commit is contained in:
commit
5427fda41e
@ -84,7 +84,7 @@ const AttendLogs = ({ Id }) => {
|
||||
document.querySelectorAll('[data-bs-toggle="tooltip"]')
|
||||
);
|
||||
tooltipTriggerList.forEach((el) => new bootstrap.Tooltip(el));
|
||||
}, [] );
|
||||
}, []);
|
||||
return (
|
||||
<div className="table-responsive">
|
||||
<div className="text-start">
|
||||
@ -106,13 +106,12 @@ const AttendLogs = ({ Id }) => {
|
||||
<table className="table table-sm mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th >Date</th>
|
||||
<th >Time</th>
|
||||
<th >Activity</th>
|
||||
<th >Location</th>
|
||||
<th >Recored By</th>
|
||||
<th >Description</th>
|
||||
|
||||
<th>Date</th>
|
||||
<th>Time</th>
|
||||
<th>Activity</th>
|
||||
<th>Location</th>
|
||||
<th>Recored By</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -141,13 +140,14 @@ const AttendLogs = ({ Id }) => {
|
||||
"--"
|
||||
)}
|
||||
</td>
|
||||
<td className="text-wrap" >
|
||||
{`${logs[0]?.updatedByEmployee?.firstName ?? ''} ${logs[0]?.updatedByEmployee?.lastName ?? ''}`}
|
||||
<td className="text-wrap">
|
||||
{`${log?.updatedByEmployee?.firstName ?? ""} ${
|
||||
log?.updatedByEmployee?.lastName ?? ""
|
||||
}`}
|
||||
</td>
|
||||
<td className="text-wrap" colSpan={3} >
|
||||
<td className="text-wrap" colSpan={3}>
|
||||
{log?.comment || "--"}
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState,useEffect } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import moment from "moment";
|
||||
import Avatar from "../common/Avatar";
|
||||
import { convertShortTime } from "../../utils/dateUtils";
|
||||
@ -32,7 +32,7 @@ const Attendance = ({ attendance, getRole, handleModalData }) => {
|
||||
|
||||
const { currentPage, totalPages, currentItems, paginate } = usePagination(
|
||||
filteredData,
|
||||
5
|
||||
10
|
||||
);
|
||||
return (
|
||||
<>
|
||||
@ -116,7 +116,7 @@ const Attendance = ({ attendance, getRole, handleModalData }) => {
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
{!attendance && (
|
||||
{!attendance && (
|
||||
<span>No employees assigned to the project</span>
|
||||
)}
|
||||
</tbody>
|
||||
|
@ -16,42 +16,57 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
|
||||
const dispatch = useDispatch();
|
||||
const { data, loading, error } = useSelector((store) => store.attendanceLogs);
|
||||
const [isRefreshing, setIsRefreshing] = useState(true);
|
||||
const [dates, setDates] = useState([]);
|
||||
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0); // Strip time to compare dates only
|
||||
|
||||
|
||||
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 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
|
||||
10
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@ -65,9 +80,17 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
|
||||
})
|
||||
);
|
||||
}
|
||||
}, [ dateRange, projectId, isRefreshing ] );
|
||||
|
||||
|
||||
}, [dateRange, projectId, isRefreshing]);
|
||||
|
||||
useEffect(() => {
|
||||
const attendanceDate = [
|
||||
...new Set(sortedFinalList.map((item) => item.checkInTime.split("T")[0])),
|
||||
].sort((a, b) => new Date(b) - new Date(a));
|
||||
if (attendanceDate != dates) {
|
||||
setDates(attendanceDate);
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
@ -80,16 +103,15 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
|
||||
<div className="col-md-2 m-0 text-end">
|
||||
<i
|
||||
className={`bx bx-refresh cursor-pointer fs-4 ${
|
||||
loading ? "spin":""
|
||||
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>
|
||||
@ -109,95 +131,111 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
|
||||
</thead>
|
||||
<tbody>
|
||||
{loading && <td colSpan={5}>Loading...</td>}
|
||||
{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">
|
||||
<RenderAttendanceStatus
|
||||
attendanceData={attendance}
|
||||
handleModalData={handleModalData}
|
||||
Tab={2}
|
||||
currentDate={currentDate}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
) )}
|
||||
{dates.map((date, i) => {
|
||||
return (
|
||||
<React.Fragment key={i}>
|
||||
{currentItems.some(
|
||||
(item) => item.checkInTime.split("T")[0] === date
|
||||
) && (
|
||||
<tr className="table-row-header">
|
||||
<td colSpan={7} className="text-start">
|
||||
<strong>{date}</strong>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
{currentItems
|
||||
?.filter((item) => item.checkInTime.includes(date))
|
||||
.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">
|
||||
<RenderAttendanceStatus
|
||||
attendanceData={attendance}
|
||||
handleModalData={handleModalData}
|
||||
Tab={2}
|
||||
currentDate={currentDate}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
) }
|
||||
{(!loading && data.length === 0) &&
|
||||
<span>No employee logs</span>
|
||||
}
|
||||
{error && <td colSpan={5}>{error}</td>}
|
||||
)}
|
||||
{!loading && data.length === 0 && <span>No employee logs</span>}
|
||||
{error && <td colSpan={5}>{error}</td>}
|
||||
</div>
|
||||
{!loading && (
|
||||
<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>
|
||||
<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>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
@ -23,11 +23,11 @@ const Regularization = ({ handleRequest }) => {
|
||||
return nameA.localeCompare(nameB);
|
||||
};
|
||||
|
||||
const filteredData = regularizesList.sort(sortByName)
|
||||
|
||||
const filteredData = regularizesList.sort(sortByName);
|
||||
|
||||
const { currentPage, totalPages, currentItems, paginate } = usePagination(
|
||||
filteredData,
|
||||
5
|
||||
10
|
||||
);
|
||||
|
||||
return (
|
||||
@ -94,50 +94,46 @@ const Regularization = ({ handleRequest }) => {
|
||||
</tbody>
|
||||
</table>
|
||||
{!loading && (
|
||||
<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>
|
||||
)}
|
||||
<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>
|
||||
);
|
||||
};
|
||||
|
@ -5,8 +5,7 @@ const EmployeeNav = ({ onPillClick, activePill }) => {
|
||||
<div className="col-md-12">
|
||||
<div className="nav-align-top ">
|
||||
<ul className="nav nav-tabs">
|
||||
|
||||
<li className="nav-item">
|
||||
<li className="nav-item" style={{ padding: "10px 10px 0 10px" }}>
|
||||
<a
|
||||
className={`nav-link py-1 px-2 small ${
|
||||
activePill === "attendance" ? "active" : ""
|
||||
@ -20,7 +19,7 @@ const EmployeeNav = ({ onPillClick, activePill }) => {
|
||||
<i className="bx bx-group bx-sm me-1_5"></i> Attendances
|
||||
</a>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<li className="nav-item" style={{ padding: "10px 10px 0 10px" }}>
|
||||
<a
|
||||
className={`nav-link py-1 px-2 small ${
|
||||
activePill === "account" ? "active" : ""
|
||||
@ -34,8 +33,8 @@ const EmployeeNav = ({ onPillClick, activePill }) => {
|
||||
<i className="bx bx-user bx-sm me-1_5"></i> Documents
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li className="nav-item">
|
||||
|
||||
<li className="nav-item" style={{ padding: "10px 10px 0 10px" }}>
|
||||
<a
|
||||
className={`nav-link py-1 px-2 small ${
|
||||
activePill === "activities" ? "active" : ""
|
||||
|
@ -54,7 +54,7 @@ const Header = () => {
|
||||
};
|
||||
|
||||
const handleProfilePage = () => {
|
||||
navigate(`/employee/${profile?.employeeInfo?.id}?for=account`);
|
||||
navigate(`/employee/${profile?.employeeInfo?.id}?for=attendance`);
|
||||
};
|
||||
return (
|
||||
<nav
|
||||
@ -120,7 +120,7 @@ const Header = () => {
|
||||
className="nav-link dropdown-toggle hide-arrow"
|
||||
href="#;"
|
||||
data-bs-toggle="dropdown"
|
||||
data-bs-auto-close="outside"
|
||||
data-bs-auto-close="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<i className="icon-base bx bx-grid-alt icon-md"></i>
|
||||
@ -143,39 +143,53 @@ const Header = () => {
|
||||
<div className="dropdown-shortcuts-list scrollable-container ps">
|
||||
<div className="row row-bordered overflow-visible g-0">
|
||||
<div className="dropdown-shortcuts-item col">
|
||||
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
|
||||
<i className="icon-base bx bx-home icon-26px text-heading"></i>
|
||||
</span>
|
||||
<a href="/dashboard" className="stretched-link">
|
||||
<a
|
||||
onClick={() => navigate(`/dashboard`)}
|
||||
className="text-heading text-truncate cursor-pointer"
|
||||
>
|
||||
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
|
||||
<i className="icon-base bx bx-home icon-26px text-heading"></i>
|
||||
</span>
|
||||
Dashboard
|
||||
</a>
|
||||
|
||||
<small>User Dashboard</small>
|
||||
</div>
|
||||
<div className="dropdown-shortcuts-item col">
|
||||
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
|
||||
<i className="icon-base bx bx-building-house icon-26px text-heading"></i>
|
||||
</span>
|
||||
<a href="/projects" className="stretched-link">
|
||||
<a
|
||||
onClick={() => navigate(`/projects`)}
|
||||
className="text-heading text-truncate cursor-pointer"
|
||||
>
|
||||
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
|
||||
<i className="icon-base bx bx-building-house icon-26px text-heading"></i>
|
||||
</span>
|
||||
Projects
|
||||
</a>
|
||||
|
||||
<small>Projects List</small>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row row-bordered overflow-visible g-0">
|
||||
<div className="dropdown-shortcuts-item col">
|
||||
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
|
||||
<i className="icon-base bx bxs-user-account icon-26px text-heading"></i>
|
||||
</span>
|
||||
<a href="/employees" className="stretched-link">
|
||||
<a
|
||||
onClick={() => navigate(`/employees`)}
|
||||
className="text-heading text-truncate cursor-pointer"
|
||||
>
|
||||
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
|
||||
<i className="icon-base bx bxs-user-account icon-26px text-heading"></i>
|
||||
</span>
|
||||
Employees
|
||||
</a>
|
||||
<small>Manage Employees</small>
|
||||
</div>
|
||||
<div className="dropdown-shortcuts-item col">
|
||||
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
|
||||
<i className="icon-base bx bx-user-check icon-26px text-heading"></i>
|
||||
</span>
|
||||
<a href="/activities/attendance" className="stretched-link">
|
||||
<a
|
||||
onClick={() => navigate(`/activities/attendance`)}
|
||||
className="text-heading text-truncate cursor-pointer"
|
||||
>
|
||||
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
|
||||
<i className="icon-base bx bx-user-check icon-26px text-heading"></i>
|
||||
</span>
|
||||
Attendance
|
||||
</a>
|
||||
<small>Manage Attendance</small>
|
||||
@ -183,21 +197,29 @@ const Header = () => {
|
||||
</div>
|
||||
<div className="row row-bordered overflow-visible g-0">
|
||||
<div className="dropdown-shortcuts-item col">
|
||||
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
|
||||
<i className="icon-base bx bxs-wrench icon-26px text-heading"></i>
|
||||
</span>
|
||||
<a href="/activities/task" className="stretched-link">
|
||||
<a
|
||||
onClick={() => navigate(`/activities/task`)}
|
||||
className="text-heading text-truncate cursor-pointer"
|
||||
>
|
||||
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
|
||||
<i className="icon-base bx bxs-wrench icon-26px text-heading"></i>
|
||||
</span>
|
||||
Allocate Work
|
||||
</a>
|
||||
|
||||
<small>Work Allocations</small>
|
||||
</div>
|
||||
<div className="dropdown-shortcuts-item col">
|
||||
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
|
||||
<i className="icon-base bx bx-list-ul icon-26px text-heading"></i>
|
||||
</span>
|
||||
<a href="/activities/records" className="stretched-link">
|
||||
<a
|
||||
onClick={() => navigate(`/activities/records`)}
|
||||
className="text-heading text-truncate cursor-pointer"
|
||||
>
|
||||
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
|
||||
<i className="icon-base bx bx-list-ul icon-26px text-heading"></i>
|
||||
</span>
|
||||
Daily Work Log
|
||||
</a>
|
||||
|
||||
<small>Daily Work Allocations</small>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -19,7 +19,7 @@ const taskSchema = z
|
||||
.object({
|
||||
activityID: z.string().min(1, "Activity is required"),
|
||||
plannedWork: z.number().min(1, "Planned Work must be greater than 0"),
|
||||
completedWork: z.number().optional(),
|
||||
completedWork: z.number().min(0, "Completed Work must be greater than 0"),
|
||||
})
|
||||
.refine(
|
||||
(data) =>
|
||||
|
@ -10,7 +10,7 @@ const taskSchema = z.object({
|
||||
workAreaId: z.string().min(1, "Work Area is required"),
|
||||
activityID: z.string().min(1, "Activity is required"),
|
||||
plannedWork: z.number().min(1, "Planned Work must be greater than 0"),
|
||||
completedWork: z.number().optional(),
|
||||
completedWork: z.number().min(0, "Completed Work must be greater than 0"),
|
||||
});
|
||||
|
||||
const defaultModel = {
|
||||
|
@ -93,11 +93,10 @@ const AttendancePage = () => {
|
||||
}, [modelConfig, isCreateModalOpen]);
|
||||
useEffect(() => {
|
||||
setAttendances(attendance);
|
||||
}, [ attendance ] );
|
||||
|
||||
}, [attendance]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedProject === 1 || selectedProject === undefined ) {
|
||||
if (selectedProject === 1 || selectedProject === undefined) {
|
||||
dispatch(setProjectId(loginUser?.projects[0]));
|
||||
}
|
||||
}, [selectedProject, loginUser?.projects]);
|
||||
|
@ -87,7 +87,6 @@ const DailyTask = () => {
|
||||
|
||||
useEffect(() => {
|
||||
popoverRefs.current.forEach((el) => {
|
||||
console.log(el);
|
||||
if (el) {
|
||||
new bootstrap.Popover(el, {
|
||||
trigger: "focus",
|
||||
@ -200,7 +199,6 @@ const DailyTask = () => {
|
||||
task.assignmentDate.includes(date)
|
||||
).map((task, index) => {
|
||||
const refIndex = index * 10 + i;
|
||||
console.log(refIndex);
|
||||
return (
|
||||
<React.Fragment key={index}>
|
||||
<tr>
|
||||
|
@ -70,7 +70,7 @@ const AttendancesEmployeeRecords = ({ employee }) => {
|
||||
const currentDate = new Date().toLocaleDateString("en-CA");
|
||||
const { currentPage, totalPages, currentItems, paginate } = usePagination(
|
||||
sortedFinalList,
|
||||
5
|
||||
10
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@ -84,7 +84,7 @@ const AttendancesEmployeeRecords = ({ employee }) => {
|
||||
})
|
||||
);
|
||||
}
|
||||
}, [dateRange, employee,isRefreshing]);
|
||||
}, [dateRange, employee, isRefreshing]);
|
||||
|
||||
const openModal = (id) => {
|
||||
setAttendanecId(id);
|
||||
@ -132,20 +132,18 @@ const AttendancesEmployeeRecords = ({ employee }) => {
|
||||
<i
|
||||
className={`bx bx-refresh cursor-pointer fs-4 ${
|
||||
loading ? "spin" : ""
|
||||
}`}
|
||||
data-toggle="tooltip"
|
||||
}`}
|
||||
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 ) && (
|
||||
{!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>
|
||||
@ -165,7 +163,7 @@ const AttendancesEmployeeRecords = ({ employee }) => {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{currentItems?.map( ( attendance, index ) => (
|
||||
{currentItems?.map((attendance, index) => (
|
||||
<tr key={index}>
|
||||
<td colSpan={2}>
|
||||
<div className="d-flex justify-content-start align-items-center">
|
||||
@ -184,12 +182,12 @@ const AttendancesEmployeeRecords = ({ employee }) => {
|
||||
</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>
|
||||
|
||||
@ -200,18 +198,18 @@ const AttendancesEmployeeRecords = ({ employee }) => {
|
||||
tabIndex="0"
|
||||
aria-controls="DataTables_Table_0"
|
||||
data-bs-toggle="modal"
|
||||
onClick={() => openModal( attendance.id )}
|
||||
onClick={() => openModal(attendance.id)}
|
||||
>
|
||||
View
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
) )}
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
) }
|
||||
)}
|
||||
</div>
|
||||
{(!loading && data.length > 5) && (
|
||||
{!loading && data.length > 5 && (
|
||||
<nav aria-label="Page ">
|
||||
<ul className="pagination pagination-sm justify-content-end py-1">
|
||||
<li
|
||||
|
@ -3,9 +3,13 @@ import EmpProfile from "../../components/Employee/EmpProfile";
|
||||
import axios from "axios";
|
||||
import Breadcrumb from "../../components/common/Breadcrumb";
|
||||
import EmployeeNav from "../../components/Employee/EmployeeNav";
|
||||
import { useSearchParams,useParams } from "react-router-dom";
|
||||
import { useSearchParams, useParams } from "react-router-dom";
|
||||
import { getCachedData } from "../../slices/apiDataManager";
|
||||
import { useEmployeeProfile, useEmployees, useEmployeesByProject } from "../../hooks/useEmployees";
|
||||
import {
|
||||
useEmployeeProfile,
|
||||
useEmployees,
|
||||
useEmployeesByProject,
|
||||
} from "../../hooks/useEmployees";
|
||||
import { useSelector } from "react-redux";
|
||||
import EmployeeRepository from "../../repositories/EmployeeRepository";
|
||||
import { ComingSoonPage } from "../Misc/ComingSoonPage";
|
||||
@ -13,41 +17,33 @@ 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)
|
||||
const {employeeId} = useParams();
|
||||
const projectID = useSelector((store) => store.localVariables.projectId);
|
||||
const { employeeId } = useParams();
|
||||
// const {employee,loading} = useEmployeeProfile(employeeId)
|
||||
const [loading,setLoading] = useState(true)
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const [SearchParams] = useSearchParams()
|
||||
const tab = SearchParams.get( "for" )
|
||||
const [SearchParams] = useSearchParams();
|
||||
const tab = SearchParams.get("for");
|
||||
const [activePill, setActivePill] = useState(tab);
|
||||
const[currentEmployee,setCurrentEmployee] = useState()
|
||||
const [currentEmployee, setCurrentEmployee] = useState();
|
||||
|
||||
|
||||
const handlePillClick = (pillKey) => {
|
||||
setActivePill(pillKey);
|
||||
};
|
||||
|
||||
const fetchEmployeeProfile = async( employeeID ) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
const resp = await EmployeeRepository.getEmployeeProfile( employeeID )
|
||||
setCurrentEmployee( resp.data )
|
||||
setLoading(false)
|
||||
|
||||
} catch ( err )
|
||||
{
|
||||
setLoading(false)
|
||||
|
||||
const fetchEmployeeProfile = async (employeeID) => {
|
||||
try {
|
||||
const resp = await EmployeeRepository.getEmployeeProfile(employeeID);
|
||||
setCurrentEmployee(resp.data);
|
||||
setLoading(false);
|
||||
} catch (err) {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if ( employeeId )
|
||||
{
|
||||
fetchEmployeeProfile(employeeId)
|
||||
if (employeeId) {
|
||||
fetchEmployeeProfile(employeeId);
|
||||
}
|
||||
}, [employeeId]);
|
||||
|
||||
@ -58,42 +54,40 @@ const EmployeeProfile = () => {
|
||||
case "attendance": {
|
||||
return (
|
||||
<>
|
||||
<AttendancesEmployeeRecords employee={employeeId } />
|
||||
|
||||
<AttendancesEmployeeRecords employee={employeeId} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
case "dcoument": {
|
||||
return (
|
||||
<>
|
||||
<ComingSoonPage/>
|
||||
</>
|
||||
<ComingSoonPage />
|
||||
</>
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "activities": {
|
||||
return (
|
||||
<>
|
||||
<ComingSoonPage/>
|
||||
</>
|
||||
<ComingSoonPage />
|
||||
</>
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return <>
|
||||
<ComingSoonPage/>
|
||||
</>;
|
||||
return (
|
||||
<>
|
||||
<ComingSoonPage />
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
if (loading) {
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className="container-xxl flex-grow-1 container-p-y">
|
||||
<Breadcrumb
|
||||
@ -123,75 +117,127 @@ const EmployeeProfile = () => {
|
||||
</div>
|
||||
<div className="w-100 d-flex flex-column justify-content-start">
|
||||
<div className="mt-3 w-100">
|
||||
<h6 className="mb-2 text-muted text-start">Employee Info</h6>
|
||||
<h6 className="mb-2 text-muted text-start">
|
||||
Employee Info
|
||||
</h6>
|
||||
<table className="table table-borderless mb-3">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="fw-medium text-start">Email:</td>
|
||||
<td className="text-start">{currentEmployee?.email || <em>NA</em>}</td>
|
||||
<td className="text-start">
|
||||
{currentEmployee?.email || <em>NA</em>}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="fw-medium text-start">Phone Number:</td>
|
||||
<td className="text-start">{currentEmployee?.phoneNumber || <em>NA</em>}</td>
|
||||
<td className="fw-medium text-start">
|
||||
Phone Number:
|
||||
</td>
|
||||
<td className="text-start">
|
||||
{currentEmployee?.phoneNumber || <em>NA</em>}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="fw-medium text-start">Emergency Contact Person:</td>
|
||||
<td className="text-start">{currentEmployee?.emergencyContactPerson || <em>NA</em>}</td>
|
||||
<td className="fw-medium text-start">
|
||||
Emergency Contact Person:
|
||||
</td>
|
||||
<td className="text-start">
|
||||
{currentEmployee?.emergencyContactPerson || (
|
||||
<em>NA</em>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="fw-medium text-start">Emergency Contact Number:</td>
|
||||
<td className="text-start">{currentEmployee?.emergencyPhoneNumber || <em>NA</em>}</td>
|
||||
<td className="fw-medium text-start">
|
||||
Emergency Contact Number:
|
||||
</td>
|
||||
<td className="text-start">
|
||||
{currentEmployee?.emergencyPhoneNumber || (
|
||||
<em>NA</em>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td className="fw-medium text-start">Gender:</td>
|
||||
<td className="text-start">{currentEmployee?.gender || <em>NA</em>}</td>
|
||||
<td className="text-start">
|
||||
{currentEmployee?.gender || <em>NA</em>}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="fw-medium text-start">Birth Date:</td>
|
||||
<td className="text-start">{currentEmployee?.birthDate ? new Date(currentEmployee.birthDate).toLocaleDateString() : <em>NA</em>}</td>
|
||||
<td className="fw-medium text-start">
|
||||
Birth Date:
|
||||
</td>
|
||||
<td className="text-start">
|
||||
{currentEmployee?.birthDate ? (
|
||||
new Date(
|
||||
currentEmployee.birthDate
|
||||
).toLocaleDateString()
|
||||
) : (
|
||||
<em>NA</em>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td className="fw-medium text-start">Joining Date:</td>
|
||||
<td className="text-start">{currentEmployee?.joiningDate ? new Date(currentEmployee.joiningDate).toLocaleDateString() : <em>NA</em>}</td>
|
||||
<td className="fw-medium text-start">
|
||||
Joining Date:
|
||||
</td>
|
||||
<td className="text-start">
|
||||
{currentEmployee?.joiningDate ? (
|
||||
new Date(
|
||||
currentEmployee.joiningDate
|
||||
).toLocaleDateString()
|
||||
) : (
|
||||
<em>NA</em>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="fw-medium text-start">Job Role:</td>
|
||||
<td className="text-start">{currentEmployee?.jobRole || <em>NA</em>}</td>
|
||||
<td className="fw-medium text-start">
|
||||
Job Role:
|
||||
</td>
|
||||
<td className="text-start">
|
||||
{currentEmployee?.jobRole || <em>NA</em>}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="fw-medium text-start">Address:</td>
|
||||
<td className="text-start">{currentEmployee?.currentAddress || <em>NA</em>}</td>
|
||||
<td className="text-start">
|
||||
{currentEmployee?.currentAddress || <em>NA</em>}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<button className="btn btn-primary btn-block" onClick={() => navigate(`/employee/manage/${currentEmployee?.id}`)}>
|
||||
<button
|
||||
className="btn btn-primary btn-block"
|
||||
onClick={() =>
|
||||
navigate(`/employee/manage/${currentEmployee?.id}`)
|
||||
}
|
||||
>
|
||||
Edit Profile
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col-12 col-lg-8 order-2 order-lg-2 mb-4">
|
||||
<div className="row">
|
||||
<EmployeeNav onPillClick={handlePillClick} activePill={activePill} />
|
||||
</div>
|
||||
<div className="card">
|
||||
<div className="row row-bordered g-0">
|
||||
{renderContent()}
|
||||
<div className="col-12 col-lg-8 order-2 order-lg-2 mb-4">
|
||||
<div className="row">
|
||||
<EmployeeNav
|
||||
onPillClick={handlePillClick}
|
||||
activePill={activePill}
|
||||
/>
|
||||
</div>
|
||||
<div className="card">
|
||||
<div className="row row-bordered g-0">{renderContent()}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -21,8 +21,7 @@ axiosClient.interceptors.request.use(
|
||||
if (token) {
|
||||
config.headers["Authorization"] = `Bearer ${token}`;
|
||||
config._retry = true;
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
config._retry = false;
|
||||
}
|
||||
}
|
||||
@ -37,7 +36,6 @@ axiosClient.interceptors.response.use(
|
||||
(response) => response,
|
||||
|
||||
async (error) => {
|
||||
|
||||
const originalRequest = error.config;
|
||||
|
||||
if (!originalRequest) {
|
||||
@ -81,17 +79,17 @@ axiosClient.interceptors.response.use(
|
||||
} else if (error.response) {
|
||||
if (error.config.url.indexOf("refresh-token") != -1) {
|
||||
//showToast("Server is unreachable. Try again later!", "error");
|
||||
}
|
||||
}
|
||||
// else {
|
||||
// // showToast(error.response.data.message, "error"); // repeted toast
|
||||
// }
|
||||
if (error.response.status === 401 && !originalRequest._retry) {
|
||||
if (error.response.status === 401) {
|
||||
originalRequest._retry = true;
|
||||
try {
|
||||
// Get the refresh token from secure storage
|
||||
const refreshToken = localStorage.getItem("refreshToken");
|
||||
|
||||
if (!refreshToken) {
|
||||
if (!refreshToken || error.response.data.errors === "Invalid or expired refresh token.") {
|
||||
// Redirect to login if refresh token is not available
|
||||
redirectToLogin();
|
||||
return Promise.reject(error);
|
||||
@ -108,7 +106,7 @@ axiosClient.interceptors.response.use(
|
||||
|
||||
const { token, refreshToken: newRefreshToken } = response.data.data;
|
||||
localStorage.setItem("jwtToken", token);
|
||||
localStorage.setItem("refreshToken", newRefreshToken);
|
||||
localStorage.setItem("refreshToken", newRefreshToken);
|
||||
|
||||
// Retry the original request with the new token
|
||||
originalRequest.headers["Authorization"] = `Bearer ${token}`;
|
||||
@ -116,7 +114,6 @@ axiosClient.interceptors.response.use(
|
||||
// Retry the original request
|
||||
return axiosClient(originalRequest);
|
||||
} catch (err) {
|
||||
|
||||
// Redirect to login if token refresh fails
|
||||
redirectToLogin();
|
||||
return Promise.reject(err);
|
||||
@ -192,5 +189,5 @@ export const api = {
|
||||
};
|
||||
//export default axiosClient;
|
||||
function redirectToLogin() {
|
||||
// window.location.href = "/auth/login";
|
||||
window.location.href = "/auth/login";
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user