Merge branch 'Issue_May_2W' of https://git.marcoaiot.com/admin/marco.pms.web into pramod_Task#186DeleteActivity

This commit is contained in:
Pramod Mahajan 2025-05-07 17:01:31 +05:30
commit 5427fda41e
13 changed files with 390 additions and 297 deletions

View File

@ -84,7 +84,7 @@ const AttendLogs = ({ Id }) => {
document.querySelectorAll('[data-bs-toggle="tooltip"]') document.querySelectorAll('[data-bs-toggle="tooltip"]')
); );
tooltipTriggerList.forEach((el) => new bootstrap.Tooltip(el)); tooltipTriggerList.forEach((el) => new bootstrap.Tooltip(el));
}, [] ); }, []);
return ( return (
<div className="table-responsive"> <div className="table-responsive">
<div className="text-start"> <div className="text-start">
@ -106,13 +106,12 @@ const AttendLogs = ({ Id }) => {
<table className="table table-sm mb-0"> <table className="table table-sm mb-0">
<thead> <thead>
<tr> <tr>
<th >Date</th> <th>Date</th>
<th >Time</th> <th>Time</th>
<th >Activity</th> <th>Activity</th>
<th >Location</th> <th>Location</th>
<th >Recored By</th> <th>Recored By</th>
<th >Description</th> <th>Description</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -141,13 +140,14 @@ const AttendLogs = ({ Id }) => {
"--" "--"
)} )}
</td> </td>
<td className="text-wrap" > <td className="text-wrap">
{`${logs[0]?.updatedByEmployee?.firstName ?? ''} ${logs[0]?.updatedByEmployee?.lastName ?? ''}`} {`${log?.updatedByEmployee?.firstName ?? ""} ${
log?.updatedByEmployee?.lastName ?? ""
}`}
</td> </td>
<td className="text-wrap" colSpan={3} > <td className="text-wrap" colSpan={3}>
{log?.comment || "--"} {log?.comment || "--"}
</td> </td>
</tr> </tr>
))} ))}
</tbody> </tbody>

View File

@ -1,4 +1,4 @@
import React, { useState,useEffect } from "react"; import React, { useState, useEffect } from "react";
import moment from "moment"; import moment from "moment";
import Avatar from "../common/Avatar"; import Avatar from "../common/Avatar";
import { convertShortTime } from "../../utils/dateUtils"; import { convertShortTime } from "../../utils/dateUtils";
@ -32,7 +32,7 @@ const Attendance = ({ attendance, getRole, handleModalData }) => {
const { currentPage, totalPages, currentItems, paginate } = usePagination( const { currentPage, totalPages, currentItems, paginate } = usePagination(
filteredData, filteredData,
5 10
); );
return ( return (
<> <>
@ -116,7 +116,7 @@ const Attendance = ({ attendance, getRole, handleModalData }) => {
</td> </td>
</tr> </tr>
))} ))}
{!attendance && ( {!attendance && (
<span>No employees assigned to the project</span> <span>No employees assigned to the project</span>
)} )}
</tbody> </tbody>

View File

@ -16,6 +16,7 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const { data, loading, error } = useSelector((store) => store.attendanceLogs); const { data, loading, error } = useSelector((store) => store.attendanceLogs);
const [isRefreshing, setIsRefreshing] = useState(true); const [isRefreshing, setIsRefreshing] = useState(true);
const [dates, setDates] = useState([]);
const today = new Date(); const today = new Date();
today.setHours(0, 0, 0, 0); // Strip time to compare dates only today.setHours(0, 0, 0, 0); // Strip time to compare dates only
@ -40,18 +41,32 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
return nameA.localeCompare(nameB); return nameA.localeCompare(nameB);
}; };
const group1 = data.filter(d => d.activity === 1 && isSameDay(d.checkInTime)).sort(sortByName); const group1 = data
const group2 = data.filter(d => d.activity === 4 && isSameDay(d.checkOutTime)).sort(sortByName); .filter((d) => d.activity === 1 && isSameDay(d.checkInTime))
const group3 = data.filter(d => d.activity === 1 && isBeforeToday(d.checkInTime)).sort(sortByName); .sort(sortByName);
const group4 = data.filter(d => d.activity === 4 && isBeforeToday(d.checkOutTime)).sort(sortByName); const group2 = data
const group5 = data.filter(d => d.activity === 5).sort(sortByName); .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 sortedFinalList = [
...group1,
...group2,
...group3,
...group4,
...group5,
];
const currentDate = new Date().toLocaleDateString( "en-CA" ); const currentDate = new Date().toLocaleDateString("en-CA");
const { currentPage, totalPages, currentItems, paginate } = usePagination( const { currentPage, totalPages, currentItems, paginate } = usePagination(
sortedFinalList, sortedFinalList,
5 10
); );
useEffect(() => { useEffect(() => {
@ -65,8 +80,16 @@ 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 ( return (
<> <>
@ -80,16 +103,15 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
<div className="col-md-2 m-0 text-end"> <div className="col-md-2 m-0 text-end">
<i <i
className={`bx bx-refresh cursor-pointer fs-4 ${ className={`bx bx-refresh cursor-pointer fs-4 ${
loading ? "spin":"" loading ? "spin" : ""
}`} }`}
title="Refresh" title="Refresh"
onClick={() => setIsRefreshing( !isRefreshing )} onClick={() => setIsRefreshing(!isRefreshing)}
/> />
</div> </div>
</div> </div>
<div className="table-responsive text-nowrap"> <div className="table-responsive text-nowrap">
{(data && data.length > 0 ) && ( {data && data.length > 0 && (
<table className="table mb-0"> <table className="table mb-0">
<thead> <thead>
<tr> <tr>
@ -109,95 +131,111 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
</thead> </thead>
<tbody> <tbody>
{loading && <td colSpan={5}>Loading...</td>} {loading && <td colSpan={5}>Loading...</td>}
{currentItems?.map( ( attendance, index ) => ( {dates.map((date, i) => {
<tr key={index}> return (
<td colSpan={2}> <React.Fragment key={i}>
<div className="d-flex justify-content-start align-items-center"> {currentItems.some(
<Avatar (item) => item.checkInTime.split("T")[0] === date
firstName={attendance.firstName} ) && (
lastName={attendance.lastName} <tr className="table-row-header">
/> <td colSpan={7} className="text-start">
<div className="d-flex flex-column"> <strong>{date}</strong>
<a href="#" className="text-heading text-truncate"> </td>
<span className="fw-normal"> </tr>
{attendance.firstName} {attendance.lastName} )}
</span> {currentItems
</a> ?.filter((item) => item.checkInTime.includes(date))
</div> .map((attendance, index) => (
</div> <tr key={index}>
</td> <td colSpan={2}>
<td> <div className="d-flex justify-content-start align-items-center">
{" "} <Avatar
{moment( attendance.checkInTime ).format( "DD-MMM-YYYY" )} firstName={attendance.firstName}
</td> lastName={attendance.lastName}
<td>{convertShortTime( attendance.checkInTime )}</td> />
<td> <div className="d-flex flex-column">
{attendance.checkOutTime <a
? convertShortTime( attendance.checkOutTime ) href="#"
: "--"} className="text-heading text-truncate"
</td> >
<td className="text-center"> <span className="fw-normal">
<RenderAttendanceStatus {attendance.firstName} {attendance.lastName}
attendanceData={attendance} </span>
handleModalData={handleModalData} </a>
Tab={2} </div>
currentDate={currentDate} </div>
/> </td>
</td> <td>
</tr> {" "}
) )} {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> </tbody>
</table> </table>
) } )}
{(!loading && data.length === 0) && {!loading && data.length === 0 && <span>No employee logs</span>}
<span>No employee logs</span> {error && <td colSpan={5}>{error}</td>}
}
{error && <td colSpan={5}>{error}</td>}
</div> </div>
{!loading && ( {!loading && (
<nav aria-label="Page "> <nav aria-label="Page ">
<ul className="pagination pagination-sm justify-content-end py-1"> <ul className="pagination pagination-sm justify-content-end py-1">
<li <li className={`page-item ${currentPage === 1 ? "disabled" : ""}`}>
className={`page-item ${ <button
currentPage === 1 ? "disabled" : "" className="page-link btn-xs"
}`} onClick={() => paginate(currentPage - 1)}
> >
<button &laquo;
className="page-link btn-xs" </button>
onClick={() => paginate(currentPage - 1)} </li>
> {[...Array(totalPages)].map((_, index) => (
&laquo; <li
</button> key={index}
</li> className={`page-item ${
{[...Array(totalPages)].map((_, index) => ( currentPage === index + 1 ? "active" : ""
<li }`}
key={index} >
className={`page-item ${ <button
currentPage === index + 1 ? "active" : "" className="page-link "
}`} onClick={() => paginate(index + 1)}
> >
<button {index + 1}
className="page-link " </button>
onClick={() => paginate(index + 1)} </li>
> ))}
{index + 1} <li
</button> className={`page-item ${
</li> currentPage === totalPages ? "disabled" : ""
))} }`}
<li >
className={`page-item ${ <button
currentPage === totalPages ? "disabled" : "" className="page-link "
}`} onClick={() => paginate(currentPage + 1)}
> >
<button &raquo;
className="page-link " </button>
onClick={() => paginate(currentPage + 1)} </li>
> </ul>
&raquo; </nav>
</button>
</li>
</ul>
</nav>
)} )}
</> </>
); );

View File

@ -23,11 +23,11 @@ const Regularization = ({ handleRequest }) => {
return nameA.localeCompare(nameB); return nameA.localeCompare(nameB);
}; };
const filteredData = regularizesList.sort(sortByName) const filteredData = regularizesList.sort(sortByName);
const { currentPage, totalPages, currentItems, paginate } = usePagination( const { currentPage, totalPages, currentItems, paginate } = usePagination(
filteredData, filteredData,
5 10
); );
return ( return (
@ -94,50 +94,46 @@ const Regularization = ({ handleRequest }) => {
</tbody> </tbody>
</table> </table>
{!loading && ( {!loading && (
<nav aria-label="Page "> <nav aria-label="Page ">
<ul className="pagination pagination-sm justify-content-end py-1"> <ul className="pagination pagination-sm justify-content-end py-1">
<li <li className={`page-item ${currentPage === 1 ? "disabled" : ""}`}>
className={`page-item ${ <button
currentPage === 1 ? "disabled" : "" className="page-link btn-xs"
}`} onClick={() => paginate(currentPage - 1)}
> >
<button &laquo;
className="page-link btn-xs" </button>
onClick={() => paginate(currentPage - 1)} </li>
> {[...Array(totalPages)].map((_, index) => (
&laquo; <li
</button> key={index}
</li> className={`page-item ${
{[...Array(totalPages)].map((_, index) => ( currentPage === index + 1 ? "active" : ""
<li }`}
key={index} >
className={`page-item ${ <button
currentPage === index + 1 ? "active" : "" className="page-link "
}`} onClick={() => paginate(index + 1)}
> >
<button {index + 1}
className="page-link " </button>
onClick={() => paginate(index + 1)} </li>
> ))}
{index + 1} <li
</button> className={`page-item ${
</li> currentPage === totalPages ? "disabled" : ""
))} }`}
<li >
className={`page-item ${ <button
currentPage === totalPages ? "disabled" : "" className="page-link "
}`} onClick={() => paginate(currentPage + 1)}
> >
<button &raquo;
className="page-link " </button>
onClick={() => paginate(currentPage + 1)} </li>
> </ul>
&raquo; </nav>
</button> )}
</li>
</ul>
</nav>
)}
</div> </div>
); );
}; };

View File

@ -5,8 +5,7 @@ const EmployeeNav = ({ onPillClick, activePill }) => {
<div className="col-md-12"> <div className="col-md-12">
<div className="nav-align-top "> <div className="nav-align-top ">
<ul className="nav nav-tabs"> <ul className="nav nav-tabs">
<li className="nav-item" style={{ padding: "10px 10px 0 10px" }}>
<li className="nav-item">
<a <a
className={`nav-link py-1 px-2 small ${ className={`nav-link py-1 px-2 small ${
activePill === "attendance" ? "active" : "" activePill === "attendance" ? "active" : ""
@ -20,7 +19,7 @@ const EmployeeNav = ({ onPillClick, activePill }) => {
<i className="bx bx-group bx-sm me-1_5"></i> Attendances <i className="bx bx-group bx-sm me-1_5"></i> Attendances
</a> </a>
</li> </li>
<li className="nav-item"> <li className="nav-item" style={{ padding: "10px 10px 0 10px" }}>
<a <a
className={`nav-link py-1 px-2 small ${ className={`nav-link py-1 px-2 small ${
activePill === "account" ? "active" : "" activePill === "account" ? "active" : ""
@ -35,7 +34,7 @@ const EmployeeNav = ({ onPillClick, activePill }) => {
</a> </a>
</li> </li>
<li className="nav-item"> <li className="nav-item" style={{ padding: "10px 10px 0 10px" }}>
<a <a
className={`nav-link py-1 px-2 small ${ className={`nav-link py-1 px-2 small ${
activePill === "activities" ? "active" : "" activePill === "activities" ? "active" : ""

View File

@ -54,7 +54,7 @@ const Header = () => {
}; };
const handleProfilePage = () => { const handleProfilePage = () => {
navigate(`/employee/${profile?.employeeInfo?.id}?for=account`); navigate(`/employee/${profile?.employeeInfo?.id}?for=attendance`);
}; };
return ( return (
<nav <nav
@ -120,7 +120,7 @@ const Header = () => {
className="nav-link dropdown-toggle hide-arrow" className="nav-link dropdown-toggle hide-arrow"
href="#;" href="#;"
data-bs-toggle="dropdown" data-bs-toggle="dropdown"
data-bs-auto-close="outside" data-bs-auto-close="true"
aria-expanded="false" aria-expanded="false"
> >
<i className="icon-base bx bx-grid-alt icon-md"></i> <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="dropdown-shortcuts-list scrollable-container ps">
<div className="row row-bordered overflow-visible g-0"> <div className="row row-bordered overflow-visible g-0">
<div className="dropdown-shortcuts-item col"> <div className="dropdown-shortcuts-item col">
<span className="dropdown-shortcuts-icon rounded-circle mb-3"> <a
<i className="icon-base bx bx-home icon-26px text-heading"></i> onClick={() => navigate(`/dashboard`)}
</span> className="text-heading text-truncate cursor-pointer"
<a href="/dashboard" className="stretched-link"> >
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
<i className="icon-base bx bx-home icon-26px text-heading"></i>
</span>
Dashboard Dashboard
</a> </a>
<small>User Dashboard</small> <small>User Dashboard</small>
</div> </div>
<div className="dropdown-shortcuts-item col"> <div className="dropdown-shortcuts-item col">
<span className="dropdown-shortcuts-icon rounded-circle mb-3"> <a
<i className="icon-base bx bx-building-house icon-26px text-heading"></i> onClick={() => navigate(`/projects`)}
</span> className="text-heading text-truncate cursor-pointer"
<a href="/projects" className="stretched-link"> >
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
<i className="icon-base bx bx-building-house icon-26px text-heading"></i>
</span>
Projects Projects
</a> </a>
<small>Projects List</small> <small>Projects List</small>
</div> </div>
</div> </div>
<div className="row row-bordered overflow-visible g-0"> <div className="row row-bordered overflow-visible g-0">
<div className="dropdown-shortcuts-item col"> <div className="dropdown-shortcuts-item col">
<span className="dropdown-shortcuts-icon rounded-circle mb-3"> <a
<i className="icon-base bx bxs-user-account icon-26px text-heading"></i> onClick={() => navigate(`/employees`)}
</span> className="text-heading text-truncate cursor-pointer"
<a href="/employees" className="stretched-link"> >
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
<i className="icon-base bx bxs-user-account icon-26px text-heading"></i>
</span>
Employees Employees
</a> </a>
<small>Manage Employees</small> <small>Manage Employees</small>
</div> </div>
<div className="dropdown-shortcuts-item col"> <div className="dropdown-shortcuts-item col">
<span className="dropdown-shortcuts-icon rounded-circle mb-3"> <a
<i className="icon-base bx bx-user-check icon-26px text-heading"></i> onClick={() => navigate(`/activities/attendance`)}
</span> className="text-heading text-truncate cursor-pointer"
<a href="/activities/attendance" className="stretched-link"> >
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
<i className="icon-base bx bx-user-check icon-26px text-heading"></i>
</span>
Attendance Attendance
</a> </a>
<small>Manage Attendance</small> <small>Manage Attendance</small>
@ -183,21 +197,29 @@ const Header = () => {
</div> </div>
<div className="row row-bordered overflow-visible g-0"> <div className="row row-bordered overflow-visible g-0">
<div className="dropdown-shortcuts-item col"> <div className="dropdown-shortcuts-item col">
<span className="dropdown-shortcuts-icon rounded-circle mb-3"> <a
<i className="icon-base bx bxs-wrench icon-26px text-heading"></i> onClick={() => navigate(`/activities/task`)}
</span> className="text-heading text-truncate cursor-pointer"
<a href="/activities/task" className="stretched-link"> >
<span className="dropdown-shortcuts-icon rounded-circle mb-3">
<i className="icon-base bx bxs-wrench icon-26px text-heading"></i>
</span>
Allocate Work Allocate Work
</a> </a>
<small>Work Allocations</small> <small>Work Allocations</small>
</div> </div>
<div className="dropdown-shortcuts-item col"> <div className="dropdown-shortcuts-item col">
<span className="dropdown-shortcuts-icon rounded-circle mb-3"> <a
<i className="icon-base bx bx-list-ul icon-26px text-heading"></i> onClick={() => navigate(`/activities/records`)}
</span> className="text-heading text-truncate cursor-pointer"
<a href="/activities/records" className="stretched-link"> >
<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 Daily Work Log
</a> </a>
<small>Daily Work Allocations</small> <small>Daily Work Allocations</small>
</div> </div>
</div> </div>

View File

@ -19,7 +19,7 @@ const taskSchema = z
.object({ .object({
activityID: z.string().min(1, "Activity is required"), activityID: z.string().min(1, "Activity is required"),
plannedWork: z.number().min(1, "Planned Work must be greater than 0"), 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( .refine(
(data) => (data) =>

View File

@ -10,7 +10,7 @@ const taskSchema = z.object({
workAreaId: z.string().min(1, "Work Area is required"), workAreaId: z.string().min(1, "Work Area is required"),
activityID: z.string().min(1, "Activity is required"), activityID: z.string().min(1, "Activity is required"),
plannedWork: z.number().min(1, "Planned Work must be greater than 0"), 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 = { const defaultModel = {

View File

@ -93,11 +93,10 @@ const AttendancePage = () => {
}, [modelConfig, isCreateModalOpen]); }, [modelConfig, isCreateModalOpen]);
useEffect(() => { useEffect(() => {
setAttendances(attendance); setAttendances(attendance);
}, [ attendance ] ); }, [attendance]);
useEffect(() => { useEffect(() => {
if (selectedProject === 1 || selectedProject === undefined ) { if (selectedProject === 1 || selectedProject === undefined) {
dispatch(setProjectId(loginUser?.projects[0])); dispatch(setProjectId(loginUser?.projects[0]));
} }
}, [selectedProject, loginUser?.projects]); }, [selectedProject, loginUser?.projects]);

View File

@ -87,7 +87,6 @@ const DailyTask = () => {
useEffect(() => { useEffect(() => {
popoverRefs.current.forEach((el) => { popoverRefs.current.forEach((el) => {
console.log(el);
if (el) { if (el) {
new bootstrap.Popover(el, { new bootstrap.Popover(el, {
trigger: "focus", trigger: "focus",
@ -200,7 +199,6 @@ const DailyTask = () => {
task.assignmentDate.includes(date) task.assignmentDate.includes(date)
).map((task, index) => { ).map((task, index) => {
const refIndex = index * 10 + i; const refIndex = index * 10 + i;
console.log(refIndex);
return ( return (
<React.Fragment key={index}> <React.Fragment key={index}>
<tr> <tr>

View File

@ -70,7 +70,7 @@ const AttendancesEmployeeRecords = ({ employee }) => {
const currentDate = new Date().toLocaleDateString("en-CA"); const currentDate = new Date().toLocaleDateString("en-CA");
const { currentPage, totalPages, currentItems, paginate } = usePagination( const { currentPage, totalPages, currentItems, paginate } = usePagination(
sortedFinalList, sortedFinalList,
5 10
); );
useEffect(() => { useEffect(() => {
@ -84,7 +84,7 @@ const AttendancesEmployeeRecords = ({ employee }) => {
}) })
); );
} }
}, [dateRange, employee,isRefreshing]); }, [dateRange, employee, isRefreshing]);
const openModal = (id) => { const openModal = (id) => {
setAttendanecId(id); setAttendanecId(id);
@ -132,7 +132,7 @@ const AttendancesEmployeeRecords = ({ employee }) => {
<i <i
className={`bx bx-refresh cursor-pointer fs-4 ${ className={`bx bx-refresh cursor-pointer fs-4 ${
loading ? "spin" : "" loading ? "spin" : ""
}`} }`}
data-toggle="tooltip" data-toggle="tooltip"
title="Refresh" title="Refresh"
onClick={() => setIsRefreshing(!isRefreshing)} onClick={() => setIsRefreshing(!isRefreshing)}
@ -140,12 +140,10 @@ const AttendancesEmployeeRecords = ({ employee }) => {
</div> </div>
</div> </div>
<div className="table-responsive text-nowrap"> <div className="table-responsive text-nowrap">
{(!loading && data.length === 0) && {!loading && data.length === 0 && <span>No employee logs</span>}
<span>No employee logs</span> {error && <div className="text-center">{error}</div>}
} {loading && !data && <div className="text-center">Loading...</div>}
{error && <div className="text-center">{error }</div>} {data && data.length > 0 && (
{(loading && !data ) && <div className="text-center">Loading...</div>}
{(data && data.length > 0 ) && (
<table className="table mb-0"> <table className="table mb-0">
<thead> <thead>
<tr> <tr>
@ -165,7 +163,7 @@ const AttendancesEmployeeRecords = ({ employee }) => {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{currentItems?.map( ( attendance, index ) => ( {currentItems?.map((attendance, index) => (
<tr key={index}> <tr key={index}>
<td colSpan={2}> <td colSpan={2}>
<div className="d-flex justify-content-start align-items-center"> <div className="d-flex justify-content-start align-items-center">
@ -184,12 +182,12 @@ const AttendancesEmployeeRecords = ({ employee }) => {
</td> </td>
<td> <td>
{" "} {" "}
{moment( attendance.checkInTime ).format( "DD-MMM-YYYY" )} {moment(attendance.checkInTime).format("DD-MMM-YYYY")}
</td> </td>
<td>{convertShortTime( attendance.checkInTime )}</td> <td>{convertShortTime(attendance.checkInTime)}</td>
<td> <td>
{attendance.checkOutTime {attendance.checkOutTime
? convertShortTime( attendance.checkOutTime ) ? convertShortTime(attendance.checkOutTime)
: "--"} : "--"}
</td> </td>
@ -200,18 +198,18 @@ const AttendancesEmployeeRecords = ({ employee }) => {
tabIndex="0" tabIndex="0"
aria-controls="DataTables_Table_0" aria-controls="DataTables_Table_0"
data-bs-toggle="modal" data-bs-toggle="modal"
onClick={() => openModal( attendance.id )} onClick={() => openModal(attendance.id)}
> >
View View
</button> </button>
</td> </td>
</tr> </tr>
) )} ))}
</tbody> </tbody>
</table> </table>
) } )}
</div> </div>
{(!loading && data.length > 5) && ( {!loading && data.length > 5 && (
<nav aria-label="Page "> <nav aria-label="Page ">
<ul className="pagination pagination-sm justify-content-end py-1"> <ul className="pagination pagination-sm justify-content-end py-1">
<li <li

View File

@ -3,9 +3,13 @@ import EmpProfile from "../../components/Employee/EmpProfile";
import axios from "axios"; import axios from "axios";
import Breadcrumb from "../../components/common/Breadcrumb"; import Breadcrumb from "../../components/common/Breadcrumb";
import EmployeeNav from "../../components/Employee/EmployeeNav"; 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 { getCachedData } from "../../slices/apiDataManager";
import { useEmployeeProfile, useEmployees, useEmployeesByProject } from "../../hooks/useEmployees"; import {
useEmployeeProfile,
useEmployees,
useEmployeesByProject,
} from "../../hooks/useEmployees";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import EmployeeRepository from "../../repositories/EmployeeRepository"; import EmployeeRepository from "../../repositories/EmployeeRepository";
import { ComingSoonPage } from "../Misc/ComingSoonPage"; import { ComingSoonPage } from "../Misc/ComingSoonPage";
@ -13,41 +17,33 @@ import { useNavigate } from "react-router-dom";
import Avatar from "../../components/common/Avatar"; import Avatar from "../../components/common/Avatar";
import AttendancesEmployeeRecords from "./AttendancesEmployeeRecords"; import AttendancesEmployeeRecords from "./AttendancesEmployeeRecords";
const EmployeeProfile = () => { const EmployeeProfile = () => {
const projectID = useSelector((store) => store.localVariables.projectId);
const projectID = useSelector((store)=>store.localVariables.projectId) const { employeeId } = useParams();
const {employeeId} = useParams();
// const {employee,loading} = useEmployeeProfile(employeeId) // const {employee,loading} = useEmployeeProfile(employeeId)
const [loading,setLoading] = useState(true) const [loading, setLoading] = useState(true);
const [SearchParams] = useSearchParams() const [SearchParams] = useSearchParams();
const tab = SearchParams.get( "for" ) const tab = SearchParams.get("for");
const [activePill, setActivePill] = useState(tab); const [activePill, setActivePill] = useState(tab);
const[currentEmployee,setCurrentEmployee] = useState() const [currentEmployee, setCurrentEmployee] = useState();
const handlePillClick = (pillKey) => { const handlePillClick = (pillKey) => {
setActivePill(pillKey); setActivePill(pillKey);
}; };
const fetchEmployeeProfile = async( employeeID ) => const fetchEmployeeProfile = async (employeeID) => {
{ try {
try const resp = await EmployeeRepository.getEmployeeProfile(employeeID);
{ setCurrentEmployee(resp.data);
const resp = await EmployeeRepository.getEmployeeProfile( employeeID ) setLoading(false);
setCurrentEmployee( resp.data ) } catch (err) {
setLoading(false) setLoading(false);
} catch ( err )
{
setLoading(false)
} }
} };
useEffect(() => { useEffect(() => {
if ( employeeId ) if (employeeId) {
{ fetchEmployeeProfile(employeeId);
fetchEmployeeProfile(employeeId)
} }
}, [employeeId]); }, [employeeId]);
@ -58,42 +54,40 @@ const EmployeeProfile = () => {
case "attendance": { case "attendance": {
return ( return (
<> <>
<AttendancesEmployeeRecords employee={employeeId } /> <AttendancesEmployeeRecords employee={employeeId} />
</> </>
); );
} }
case "dcoument": { case "dcoument": {
return ( return (
<> <>
<ComingSoonPage/> <ComingSoonPage />
</> </>
); );
break; break;
} }
case "activities": { case "activities": {
return ( return (
<> <>
<ComingSoonPage/> <ComingSoonPage />
</> </>
); );
break; break;
} }
default: default:
return <> return (
<ComingSoonPage/> <>
</>; <ComingSoonPage />
</>
);
} }
}; };
if (loading) { if (loading) {
return <div>Loading...</div>; return <div>Loading...</div>;
} }
return ( return (
<div className="container-xxl flex-grow-1 container-p-y"> <div className="container-xxl flex-grow-1 container-p-y">
<Breadcrumb <Breadcrumb
@ -123,75 +117,127 @@ const EmployeeProfile = () => {
</div> </div>
<div className="w-100 d-flex flex-column justify-content-start"> <div className="w-100 d-flex flex-column justify-content-start">
<div className="mt-3 w-100"> <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"> <table className="table table-borderless mb-3">
<tbody> <tbody>
<tr> <tr>
<td className="fw-medium text-start">Email:</td> <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>
<tr> <tr>
<td className="fw-medium text-start">Phone Number:</td> <td className="fw-medium text-start">
<td className="text-start">{currentEmployee?.phoneNumber || <em>NA</em>}</td> Phone Number:
</td>
<td className="text-start">
{currentEmployee?.phoneNumber || <em>NA</em>}
</td>
</tr> </tr>
<tr> <tr>
<td className="fw-medium text-start">Emergency Contact Person:</td> <td className="fw-medium text-start">
<td className="text-start">{currentEmployee?.emergencyContactPerson || <em>NA</em>}</td> Emergency Contact Person:
</td>
<td className="text-start">
{currentEmployee?.emergencyContactPerson || (
<em>NA</em>
)}
</td>
</tr> </tr>
<tr> <tr>
<td className="fw-medium text-start">Emergency Contact Number:</td> <td className="fw-medium text-start">
<td className="text-start">{currentEmployee?.emergencyPhoneNumber || <em>NA</em>}</td> Emergency Contact Number:
</td>
<td className="text-start">
{currentEmployee?.emergencyPhoneNumber || (
<em>NA</em>
)}
</td>
</tr> </tr>
<tr> <tr>
<td className="fw-medium text-start">Gender:</td> <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>
<tr> <tr>
<td className="fw-medium text-start">Birth Date:</td> <td className="fw-medium text-start">
<td className="text-start">{currentEmployee?.birthDate ? new Date(currentEmployee.birthDate).toLocaleDateString() : <em>NA</em>}</td> Birth Date:
</td>
<td className="text-start">
{currentEmployee?.birthDate ? (
new Date(
currentEmployee.birthDate
).toLocaleDateString()
) : (
<em>NA</em>
)}
</td>
</tr> </tr>
<tr> <tr>
<td className="fw-medium text-start">Joining Date:</td> <td className="fw-medium text-start">
<td className="text-start">{currentEmployee?.joiningDate ? new Date(currentEmployee.joiningDate).toLocaleDateString() : <em>NA</em>}</td> Joining Date:
</td>
<td className="text-start">
{currentEmployee?.joiningDate ? (
new Date(
currentEmployee.joiningDate
).toLocaleDateString()
) : (
<em>NA</em>
)}
</td>
</tr> </tr>
<tr> <tr>
<td className="fw-medium text-start">Job Role:</td> <td className="fw-medium text-start">
<td className="text-start">{currentEmployee?.jobRole || <em>NA</em>}</td> Job Role:
</td>
<td className="text-start">
{currentEmployee?.jobRole || <em>NA</em>}
</td>
</tr> </tr>
<tr> <tr>
<td className="fw-medium text-start">Address:</td> <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> </tr>
</tbody> </tbody>
</table> </table>
</div> </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 Edit Profile
</button> </button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div className="col-12 col-lg-8 order-2 order-lg-2 mb-4"> <div className="col-12 col-lg-8 order-2 order-lg-2 mb-4">
<div className="row"> <div className="row">
<EmployeeNav onPillClick={handlePillClick} activePill={activePill} /> <EmployeeNav
</div> onPillClick={handlePillClick}
<div className="card"> activePill={activePill}
<div className="row row-bordered g-0"> />
{renderContent()} </div>
<div className="card">
<div className="row row-bordered g-0">{renderContent()}</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
); );
}; };

View File

@ -21,8 +21,7 @@ axiosClient.interceptors.request.use(
if (token) { if (token) {
config.headers["Authorization"] = `Bearer ${token}`; config.headers["Authorization"] = `Bearer ${token}`;
config._retry = true; config._retry = true;
} } else {
else{
config._retry = false; config._retry = false;
} }
} }
@ -37,7 +36,6 @@ axiosClient.interceptors.response.use(
(response) => response, (response) => response,
async (error) => { async (error) => {
const originalRequest = error.config; const originalRequest = error.config;
if (!originalRequest) { if (!originalRequest) {
@ -85,13 +83,13 @@ axiosClient.interceptors.response.use(
// else { // else {
// // showToast(error.response.data.message, "error"); // repeted toast // // showToast(error.response.data.message, "error"); // repeted toast
// } // }
if (error.response.status === 401 && !originalRequest._retry) { if (error.response.status === 401) {
originalRequest._retry = true; originalRequest._retry = true;
try { try {
// Get the refresh token from secure storage // Get the refresh token from secure storage
const refreshToken = localStorage.getItem("refreshToken"); 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 // Redirect to login if refresh token is not available
redirectToLogin(); redirectToLogin();
return Promise.reject(error); return Promise.reject(error);
@ -116,7 +114,6 @@ axiosClient.interceptors.response.use(
// Retry the original request // Retry the original request
return axiosClient(originalRequest); return axiosClient(originalRequest);
} catch (err) { } catch (err) {
// Redirect to login if token refresh fails // Redirect to login if token refresh fails
redirectToLogin(); redirectToLogin();
return Promise.reject(err); return Promise.reject(err);
@ -192,5 +189,5 @@ export const api = {
}; };
//export default axiosClient; //export default axiosClient;
function redirectToLogin() { function redirectToLogin() {
// window.location.href = "/auth/login"; window.location.href = "/auth/login";
} }