Compare commits

..

No commits in common. "5427fda41ef1b1c4d71f7e16bf456dd5b5b376fb" and "9e3101ebf43238f33b56f4a8a5be97ff4a4219ed" have entirely different histories.

23 changed files with 482 additions and 441 deletions

View File

@ -112,6 +112,7 @@ const AttendLogs = ({ Id }) => {
<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>
@ -126,7 +127,7 @@ const AttendLogs = ({ Id }) => {
<td> <td>
{log?.latitude != 0 ? ( {log?.latitude != 0 ? (
<i <i
className="bx bx-location-plus text-danger cursor-pointer" class="bx bx-location-plus text-danger cursor-pointer"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
data-bs-offset="0,8" data-bs-offset="0,8"
data-bs-placement="top" data-bs-placement="top"
@ -141,13 +142,12 @@ const AttendLogs = ({ Id }) => {
)} )}
</td> </td>
<td className="text-wrap" > <td className="text-wrap" >
{`${log?.updatedByEmployee?.firstName ?? ""} ${ {`${logs[0]?.updatedByEmployee?.firstName ?? ''} ${logs[0]?.updatedByEmployee?.lastName ?? ''}`}
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

@ -32,7 +32,7 @@ const Attendance = ({ attendance, getRole, handleModalData }) => {
const { currentPage, totalPages, currentItems, paginate } = usePagination( const { currentPage, totalPages, currentItems, paginate } = usePagination(
filteredData, filteredData,
10 5
); );
return ( return (
<> <>

View File

@ -16,7 +16,6 @@ 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
@ -41,32 +40,18 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
return nameA.localeCompare(nameB); return nameA.localeCompare(nameB);
}; };
const group1 = data const group1 = data.filter(d => d.activity === 1 && isSameDay(d.checkInTime)).sort(sortByName);
.filter((d) => d.activity === 1 && isSameDay(d.checkInTime)) const group2 = data.filter(d => d.activity === 4 && isSameDay(d.checkOutTime)).sort(sortByName);
.sort(sortByName); const group3 = data.filter(d => d.activity === 1 && isBeforeToday(d.checkInTime)).sort(sortByName);
const group2 = data const group4 = data.filter(d => d.activity === 4 && isBeforeToday(d.checkOutTime)).sort(sortByName);
.filter((d) => d.activity === 4 && isSameDay(d.checkOutTime)) const group5 = data.filter(d => d.activity === 5).sort(sortByName);
.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 = [ const sortedFinalList = [...group1, ...group2, ...group3, ...group4, ...group5];
...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,
10 5
); );
useEffect(() => { useEffect(() => {
@ -82,14 +67,6 @@ 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 (
<> <>
@ -107,11 +84,12 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
}`} }`}
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>
@ -131,21 +109,7 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
</thead> </thead>
<tbody> <tbody>
{loading && <td colSpan={5}>Loading...</td>} {loading && <td colSpan={5}>Loading...</td>}
{dates.map((date, i) => { {currentItems?.map( ( attendance, index ) => (
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}> <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">
@ -154,10 +118,7 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
lastName={attendance.lastName} lastName={attendance.lastName}
/> />
<div className="d-flex flex-column"> <div className="d-flex flex-column">
<a <a href="#" className="text-heading text-truncate">
href="#"
className="text-heading text-truncate"
>
<span className="fw-normal"> <span className="fw-normal">
{attendance.firstName} {attendance.lastName} {attendance.firstName} {attendance.lastName}
</span> </span>
@ -167,9 +128,7 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
</td> </td>
<td> <td>
{" "} {" "}
{moment(attendance.checkInTime).format( {moment( attendance.checkInTime ).format( "DD-MMM-YYYY" )}
"DD-MMM-YYYY"
)}
</td> </td>
<td>{convertShortTime( attendance.checkInTime )}</td> <td>{convertShortTime( attendance.checkInTime )}</td>
<td> <td>
@ -187,19 +146,22 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
</td> </td>
</tr> </tr>
) )} ) )}
</React.Fragment>
);
})}
</tbody> </tbody>
</table> </table>
) } ) }
{!loading && data.length === 0 && <span>No employee logs</span>} {(!loading && data.length === 0) &&
<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 className={`page-item ${currentPage === 1 ? "disabled" : ""}`}> <li
className={`page-item ${
currentPage === 1 ? "disabled" : ""
}`}
>
<button <button
className="page-link btn-xs" className="page-link btn-xs"
onClick={() => paginate(currentPage - 1)} onClick={() => paginate(currentPage - 1)}

View File

@ -52,7 +52,49 @@ const InfraPlanning = () =>
))} ))}
</select> </select>
</div> </div>
{/* <div className={`col-12 text-end mb-1 ${!ManageInfra && 'd-none'} `} >
<button
type="button"
className="link-button link-button-sm m-1 "
data-bs-toggle="modal"
data-bs-target="#building-model"
// onClick={() => openBuildingModel()}
>
<i className="bx bx-plus-circle me-2"></i>
Manage Building
</button>
<button
type="button"
data-bs-toggle="modal"
className="link-button m-1"
data-bs-target="#floor-model"
// onClick={() => openFloorModel()}
>
<i className="bx bx-plus-circle me-2"></i>
Manage Floors
</button>
<button
type="button"
data-bs-toggle="modal"
className="link-button m-1"
data-bs-target="#work-area-model"
// onClick={() => openWorkAreaModel()}
>
<i className="bx bx-plus-circle me-2"></i>
Manage Work Areas
</button>
<button
type="button"
data-bs-toggle="modal"
className="link-button m-1"
data-bs-target="#task-model"
// onClick={() => openTaskModel()}
>
<i className="bx bx-plus-circle me-2"></i>
Manage Tasks
</button>
</div> */}
</div> </div>
<div className="row "> <div className="row ">
{project_deatilsLoader && ( <p>Loading...</p> )} {project_deatilsLoader && ( <p>Loading...</p> )}

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,
10 5
); );
return ( return (
@ -96,7 +96,11 @@ const Regularization = ({ handleRequest }) => {
{!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 className={`page-item ${currentPage === 1 ? "disabled" : ""}`}> <li
className={`page-item ${
currentPage === 1 ? "disabled" : ""
}`}
>
<button <button
className="page-link btn-xs" className="page-link btn-xs"
onClick={() => paginate(currentPage - 1)} onClick={() => paginate(currentPage - 1)}

View File

@ -5,7 +5,8 @@ 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" : ""
@ -19,7 +20,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" 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 === "account" ? "active" : "" activePill === "account" ? "active" : ""
@ -34,7 +35,7 @@ const EmployeeNav = ({ onPillClick, activePill }) => {
</a> </a>
</li> </li>
<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 === "activities" ? "active" : "" activePill === "activities" ? "active" : ""

View File

@ -54,7 +54,7 @@ const Header = () => {
}; };
const handleProfilePage = () => { const handleProfilePage = () => {
navigate(`/employee/${profile?.employeeInfo?.id}?for=attendance`); navigate(`/employee/${profile?.employeeInfo?.id}?for=account`);
}; };
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="true" data-bs-auto-close="outside"
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,53 +143,39 @@ 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">
<a
onClick={() => navigate(`/dashboard`)}
className="text-heading text-truncate cursor-pointer"
>
<span className="dropdown-shortcuts-icon rounded-circle mb-3"> <span className="dropdown-shortcuts-icon rounded-circle mb-3">
<i className="icon-base bx bx-home icon-26px text-heading"></i> <i className="icon-base bx bx-home icon-26px text-heading"></i>
</span> </span>
<a href="/dashboard" className="stretched-link">
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">
<a
onClick={() => navigate(`/projects`)}
className="text-heading text-truncate cursor-pointer"
>
<span className="dropdown-shortcuts-icon rounded-circle mb-3"> <span className="dropdown-shortcuts-icon rounded-circle mb-3">
<i className="icon-base bx bx-building-house icon-26px text-heading"></i> <i className="icon-base bx bx-building-house icon-26px text-heading"></i>
</span> </span>
<a href="/projects" className="stretched-link">
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">
<a
onClick={() => navigate(`/employees`)}
className="text-heading text-truncate cursor-pointer"
>
<span className="dropdown-shortcuts-icon rounded-circle mb-3"> <span className="dropdown-shortcuts-icon rounded-circle mb-3">
<i className="icon-base bx bxs-user-account icon-26px text-heading"></i> <i className="icon-base bx bxs-user-account icon-26px text-heading"></i>
</span> </span>
<a href="/employees" className="stretched-link">
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">
<a
onClick={() => navigate(`/activities/attendance`)}
className="text-heading text-truncate cursor-pointer"
>
<span className="dropdown-shortcuts-icon rounded-circle mb-3"> <span className="dropdown-shortcuts-icon rounded-circle mb-3">
<i className="icon-base bx bx-user-check icon-26px text-heading"></i> <i className="icon-base bx bx-user-check icon-26px text-heading"></i>
</span> </span>
<a href="/activities/attendance" className="stretched-link">
Attendance Attendance
</a> </a>
<small>Manage Attendance</small> <small>Manage Attendance</small>
@ -197,29 +183,21 @@ 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">
<a
onClick={() => navigate(`/activities/task`)}
className="text-heading text-truncate cursor-pointer"
>
<span className="dropdown-shortcuts-icon rounded-circle mb-3"> <span className="dropdown-shortcuts-icon rounded-circle mb-3">
<i className="icon-base bx bxs-wrench icon-26px text-heading"></i> <i className="icon-base bx bxs-wrench icon-26px text-heading"></i>
</span> </span>
<a href="/activities/task" className="stretched-link">
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">
<a
onClick={() => navigate(`/activities/records`)}
className="text-heading text-truncate cursor-pointer"
>
<span className="dropdown-shortcuts-icon rounded-circle mb-3"> <span className="dropdown-shortcuts-icon rounded-circle mb-3">
<i className="icon-base bx bx-list-ul icon-26px text-heading"></i> <i className="icon-base bx bx-list-ul icon-26px text-heading"></i>
</span> </span>
<a href="/activities/records" className="stretched-link">
Daily Work Log Daily Work Log
</a> </a>
<small>Daily Work Allocations</small> <small>Daily Work Allocations</small>
</div> </div>
</div> </div>

View File

@ -0,0 +1,104 @@
import React, {useState} from 'react'
import ProjectRepository from '../../../repositories/ProjectRepository'
import {useProjectDetails} from '../../../hooks/useProjects'
const DleleteActivity = ( {workItem, workArea, building, floor, onClose} ) =>
{
const {projects_Details, refetch} = useProjectDetails()
const [loading,setLoading] = useState(false)
const handleDeleteActivity =async () =>
{
try
{
setLoading(false)
const updatedProject = { ...projects_Details };
const response = await ProjectRepository.deleteProjectTask( workItem.workItemId );
const newProject = {
...updatedProject,
buildings: updatedProject.buildings.map((building) =>
building.id === building.buildingID
? {
...building,
floors: building.floors.map((floor) =>
floor.id === building.floorId
? {
...floor,
workAreas: floor.workAreas.map((workArea) =>
workArea.id === workItem?.workAreaId
? {
...workArea,
workItems: (() => {
const exists = workArea.workItems.some(
(item) =>
String(
item?.workItem?.id ?? item?.id
) === String(finalData.id)
);
finalUpdatedWorkItem = workItem;
return exists
? workArea.workItems.map((item) =>
String(
item?.workItem?.id ?? item?.id
) === String(finalData.id)
? workItem
: item
)
: [...workArea.workItems, workItem];
})(),
}
: workArea
),
}
: floor
),
}
: building
),
};
cacheData("projectInfo", {
projectId: newProject.id,
data: newProject,
});
resetForm();
dispatch( refreshData( true ) );
setLoading(false)
showToast("Activity Updated Successfully","success")
onClose();
} catch ( error )
{
console.log(error)
}
}
return (
<div className="modal-dialog modal-md modal-simple modal-edit-user">
<div className='modal-dialog modal-dialog-centered'>
<div className="modal-content">
<div className="modal-body">
<div className="row">
<button
type="button"
className="btn-close"
aria-label="Close"
onClick={()=>onClose}
/>
<div className="text-center mb-1">
<h5>Are you sure you want delete this Activity { workItem.id}</h5>
<div className='d-flex justify-content-evenly'>
<button className='btn btn-primary btn-xs' onClick={handleDeleteActivity}>{ loading ? "Please Wait ":"Yes"}</button>
<button className='btn btn-secondary btn-xs' onClick={()=>onClose}>Cancel</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
export default DleleteActivity

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().min(0, "Completed Work must be greater than 0"), completedWork: z.number().optional(),
}) })
.refine( .refine(
(data) => (data) =>

View File

@ -205,7 +205,7 @@ const FloorModel = ({
{formData.buildingId !== "0" && ( {formData.buildingId !== "0" && (
<div className="col-12 col-md-12"> <div className="col-12 col-md-12">
<label className="form-label" > <label className="form-label" htmlFor="floorName">
{formData.id !== "0" ? "Modify " : "Enter "} Floor Name {formData.id !== "0" ? "Modify " : "Enter "} Floor Name
</label> </label>
<input <input

View File

@ -68,7 +68,7 @@ const InfraTable = ({ buildings }) => {
showToast("Failed to save floor", "error"); showToast("Failed to save floor", "error");
} }
} catch (err) { } catch (err) {
console.error("Error adding floor", err);
showToast("Error occurred while saving floor", "error"); showToast("Error occurred while saving floor", "error");
} }
}; };

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().min(0, "Completed Work must be greater than 0"), completedWork: z.number().optional(),
}); });
const defaultModel = { const defaultModel = {

View File

@ -29,7 +29,7 @@ const WorkArea = ({ workArea, floor, forBuilding }) => {
<span className="fw-semibold text-primary"> <span className="fw-semibold text-primary">
Floor:&nbsp; Floor:&nbsp;
</span>{" "} </span>{" "}
<span className="fw-normal text-darkgreen"> <span class="fw-normal text-darkgreen">
{floor.floorName} {floor.floorName}
</span> </span>
</div> </div>
@ -37,7 +37,7 @@ const WorkArea = ({ workArea, floor, forBuilding }) => {
<span className="ms-10 fw-semibold text-primary"> <span className="ms-10 fw-semibold text-primary">
Work Area:&nbsp; Work Area:&nbsp;
</span>{" "} </span>{" "}
<span className=" fw-normal text-darkgreen"> <span class=" fw-normal text-darkgreen">
{workArea.areaName} {workArea.areaName}
</span> </span>
</div> </div>

View File

@ -4,12 +4,12 @@ import { useParams } from "react-router-dom";
import EditActivityModal from "./EditActivityModal"; import EditActivityModal from "./EditActivityModal";
import { useHasUserPermission } from "../../../hooks/useHasUserPermission"; import { useHasUserPermission } from "../../../hooks/useHasUserPermission";
import { MANAGE_PROJECT_INFRA, MANAGE_TASK } from "../../../utils/constants"; import { MANAGE_PROJECT_INFRA, MANAGE_TASK } from "../../../utils/constants";
import DleleteActivity from "./DleleteActivity";
import ConfirmModal from "../../common/ConfirmModal"; import ConfirmModal from "../../common/ConfirmModal";
import ProjectRepository from '../../../repositories/ProjectRepository' import ProjectRepository from '../../../repositories/ProjectRepository'
import {useProjectDetails} from '../../../hooks/useProjects' import {useProjectDetails} from '../../../hooks/useProjects'
import showToast from "../../../services/toastService"; import showToast from "../../../services/toastService";
import {cacheData, getCachedData} from "../../../slices/apiDataManager"; import {cacheData} from "../../../slices/apiDataManager";
import {useDispatch} from "react-redux"; import {useDispatch} from "react-redux";
import {refreshData} from "../../../slices/localVariablesSlice"; import {refreshData} from "../../../slices/localVariablesSlice";
@ -23,10 +23,9 @@ const WorkItem = ({ workItem, forBuilding, forFloor, forWorkArea }) => {
const ManageTasks = useHasUserPermission(MANAGE_TASK); const ManageTasks = useHasUserPermission(MANAGE_TASK);
const ManageInfra = useHasUserPermission( MANAGE_PROJECT_INFRA ); const ManageInfra = useHasUserPermission( MANAGE_PROJECT_INFRA );
const [ loadingDelete, setLoadingDelete ] = useState( false ) const [ loadingDelete, setLoadingDelete ] = useState( false )
const project = getCachedData("projectInfo");
const dispatch = useDispatch() const dispatch = useDispatch()
const {projects_Details} = useProjectDetails(projectId || project?.projectId) const {projects_Details} = useProjectDetails(projectId)
const openModal = () => setIsModalOpen(true); const openModal = () => setIsModalOpen(true);
const closeModal = () => setIsModalOpen(false); const closeModal = () => setIsModalOpen(false);
@ -64,6 +63,7 @@ const WorkItem = ({ workItem, forBuilding, forFloor, forWorkArea }) => {
const showModalDelete = () => setShowModal2(true); const showModalDelete = () => setShowModal2(true);
const closeModalDelete = () => setShowModal2( false ); const closeModalDelete = () => setShowModal2( false );
console.log(workItem)
const handleSubmit = async() => { const handleSubmit = async() => {
setLoadingDelete(true); setLoadingDelete(true);
@ -103,25 +103,27 @@ const WorkItem = ({ workItem, forBuilding, forFloor, forWorkArea }) => {
), ),
}; };
console.log(newProject)
cacheData("projectInfo", { cacheData("projectInfo", {
projectId: newProject.id, projectId: newProject.id,
data: newProject, data: newProject,
}); });
dispatch( refreshData( true ) ); dispatch( refreshData( true ) );
closeModalDelete()
setLoadingDelete(false) setLoadingDelete(false)
showToast("Activity Deleted Successfully","success") showToast("Activity Updated Successfully","success")
} catch ( error ) } catch ( error )
{ {
setLoadingDelete(false) setLoadingDelete(false)
closeModalDelete()
const message = const message =
error.response?.data?.message || error.response?.data?.message ||
error.message || error.message ||
"An unexpected error occurred"; "An unexpected error occurred";
showToast( message, "error" ); showToast( message, "error" );
console.log(error)
} }
}; };
return ( return (
@ -154,7 +156,6 @@ const WorkItem = ({ workItem, forBuilding, forFloor, forWorkArea }) => {
/> />
</div>} </div>}
{showModal2 && <div {showModal2 && <div
className={`modal fade ${showModal2 ? "show" : ""}`} className={`modal fade ${showModal2 ? "show" : ""}`}
tabIndex="-1" tabIndex="-1"
@ -162,7 +163,14 @@ const WorkItem = ({ workItem, forBuilding, forFloor, forWorkArea }) => {
style={{ display: showModal2 ? "block" : "none" }} style={{ display: showModal2 ? "block" : "none" }}
aria-hidden='false' aria-hidden='false'
> >
<ConfirmModal type={"delete"} header={"Delete Activity"} message={"Are you sure you want delete"} onSubmit={ handleSubmit} onClose={closeModalDelete} loading={loadingDelete}/> {/* <DleleteActivity
workItem={workItem}
workArea={forWorkArea}
building={forBuilding}
floor={forFloor}
onClose={closeModalDelete}
/> */}
<ConfirmModal type={"delete"} message={"Are you sure you want delete"} onSubmit={ handleSubmit} onClose={closeModalDelete} loading={loadingDelete}/>
</div> } </div> }
<tr> <tr>

View File

@ -1,11 +1,11 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
const ConfirmModal = ({ type, onSubmit, onClose, message, loading ,header}) => { const ConfirmModal = ({ type, onSubmit, onClose, message, loading }) => {
const TypeofIcon = (type) => { const TypeofIcon = (type) => {
switch (type) { switch (type) {
case "delete": case "delete":
return <i className='bx bx-x-circle text-danger ' style={{fontSize:"60px"}} ></i>; return <i className='bx bx-x-circle text-danger bx-lg'></i>;
default: default:
return null; return null;
} }
@ -34,15 +34,9 @@ const ConfirmModal = ({ type, onSubmit, onClose, message, loading ,header}) => {
aria-label="Close" aria-label="Close"
onClick={onClose} onClick={onClose}
/> />
<div className="text-start mb-1"> <div className="text-center mb-1">
<p className='fs-6'>{TypeofIcon(type)} <span className='fs-6'>{message}</span></p>
<div className='d-flex justify-content-evenly'>
{header && < strong className='mb-0 font-weight-bold'>{header }</strong>}
<div className='row'>
<div className='col-4 col-sm-2'> {TypeofIcon(type)}</div>
<div className='col-8 col-sm-10 py-sm-2 py-1 text-sm-end'>
<span className='fs-6 text'>{message}</span>
<div className='d-flex justify-content-center mt-4'>
<button <button
className='btn btn-primary btn-sm' className='btn btn-primary btn-sm'
onClick={onSubmit} onClick={onSubmit}
@ -51,7 +45,7 @@ const ConfirmModal = ({ type, onSubmit, onClose, message, loading ,header}) => {
{loading ? "Please Wait..." : "Yes"} {loading ? "Please Wait..." : "Yes"}
</button> </button>
<button <button
className='btn btn-secondary ms-4 btn-sm' className='btn btn-secondary btn-sm'
onClick={onClose} onClick={onClose}
disabled={loading} disabled={loading}
> >
@ -60,10 +54,6 @@ const ConfirmModal = ({ type, onSubmit, onClose, message, loading ,header}) => {
</div> </div>
</div> </div>
</div> </div>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -204,7 +204,7 @@ const CreateActivity = ({ onClose }) => {
onClick={() => removeChecklistItem(index)} onClick={() => removeChecklistItem(index)}
className="btn btn-xs btn-icon btn-text-secondary" className="btn btn-xs btn-icon btn-text-secondary"
> >
<i className="bx bxs-minus-circle text-danger" data-bs-toggle="tooltip" <i class="bx bxs-minus-circle text-danger" data-bs-toggle="tooltip"
title="Remove Check" title="Remove Check"
data-bs-original-title="Remove check"></i> data-bs-original-title="Remove check"></i>
</button> </button>
@ -219,7 +219,7 @@ const CreateActivity = ({ onClose }) => {
className="btn btn-xs btn-primary mt-2" className="btn btn-xs btn-primary mt-2"
onClick={addChecklistItem} onClick={addChecklistItem}
> >
<i className="bx bx-plus-circle" data-bs-toggle="tooltip" <i class="bx bx-plus-circle" data-bs-toggle="tooltip"
title="Add Check" title="Add Check"
data-bs-original-title="Add check" ></i> data-bs-original-title="Add check" ></i>
</button> </button>

View File

@ -62,7 +62,7 @@ const AttendancePage = () => {
modalElement.classList.remove("show"); modalElement.classList.remove("show");
modalElement.style.display = "none"; modalElement.style.display = "none";
document.body.classList.remove("modal-open"); document.body.classList.remove("modal-open");
document.querySelector(".modal-backdrop")?.remove(); document.querySelector(".modal-backdrop").remove();
} }
}; };
@ -95,6 +95,7 @@ const AttendancePage = () => {
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]));
@ -107,7 +108,7 @@ const AttendancePage = () => {
className="modal fade show" className="modal fade show"
style={{ display: "block" }} style={{ display: "block" }}
id="check-Out-modal" id="check-Out-modal"
tabIndex="-1" tabindex="-1"
aria-hidden="true" aria-hidden="true"
> >
<AttendanceModel <AttendanceModel

View File

@ -87,6 +87,7 @@ 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",
@ -199,6 +200,7 @@ 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

@ -9,7 +9,6 @@ import { useProfile } from "../../hooks/useProfile";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { useProjectDetails, useProjects } from "../../hooks/useProjects"; import { useProjectDetails, useProjects } from "../../hooks/useProjects";
import { setProjectId } from "../../slices/localVariablesSlice"; import { setProjectId } from "../../slices/localVariablesSlice";
import showToast from "../../services/toastService";
const TaskPlannng = () => { const TaskPlannng = () => {
const { profile } = useProfile(); const { profile } = useProfile();
@ -23,7 +22,6 @@ const TaskPlannng = () => {
(store) => store.localVariables.projectId (store) => store.localVariables.projectId
); );
const [project, setProject] = useState(null); const [project, setProject] = useState(null);
const [projectDetails, setProjectDetails] = useState(null); const [projectDetails, setProjectDetails] = useState(null);
const [activities, setActivities] = useState(null); const [activities, setActivities] = useState(null);
@ -68,22 +66,14 @@ const TaskPlannng = () => {
}); });
}) })
.catch((error) => { .catch((error) => {
const message = console.error(error);
error.response?.data?.message || setError("Failed to fetch data.");
error.message ||
"An unexpected error occurred";
showToast( message, "error" );
}); });
} else { } else {
setProjectDetails(project_cache); setProjectDetails(project_cache);
} }
} catch (err) { } catch (err) {
setError("Failed to fetch data."); setError("Failed to fetch data.");
const message =
error.response?.data?.message ||
error.message ||
"An unexpected error occurred";
showToast( message, "error" );
} finally { } finally {
setLoading(false); setLoading(false);
} }

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,
10 5
); );
useEffect(() => { useEffect(() => {
@ -140,10 +140,12 @@ const AttendancesEmployeeRecords = ({ employee }) => {
</div> </div>
</div> </div>
<div className="table-responsive text-nowrap"> <div className="table-responsive text-nowrap">
{!loading && data.length === 0 && <span>No employee logs</span>} {(!loading && data.length === 0) &&
<span>No employee logs</span>
}
{error && <div className="text-center">{error }</div>} {error && <div className="text-center">{error }</div>}
{loading && !data && <div className="text-center">Loading...</div>} {(loading && !data ) && <div className="text-center">Loading...</div>}
{data && data.length > 0 && ( {(data && data.length > 0 ) && (
<table className="table mb-0"> <table className="table mb-0">
<thead> <thead>
<tr> <tr>
@ -209,7 +211,7 @@ const AttendancesEmployeeRecords = ({ employee }) => {
</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

@ -5,11 +5,7 @@ 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 { import { useEmployeeProfile, useEmployees, useEmployeesByProject } from "../../hooks/useEmployees";
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";
@ -17,33 +13,41 @@ 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 { {
const resp = await EmployeeRepository.getEmployeeProfile(employeeID); try
setCurrentEmployee(resp.data); {
setLoading(false); const resp = await EmployeeRepository.getEmployeeProfile( employeeID )
} catch (err) { setCurrentEmployee( resp.data )
setLoading(false); setLoading(false)
} catch ( err )
{
setLoading(false)
}
} }
};
useEffect(() => { useEffect(() => {
if (employeeId) { if ( employeeId )
fetchEmployeeProfile(employeeId); {
fetchEmployeeProfile(employeeId)
} }
}, [employeeId]); }, [employeeId]);
@ -55,6 +59,7 @@ const EmployeeProfile = () => {
return ( return (
<> <>
<AttendancesEmployeeRecords employee={employeeId } /> <AttendancesEmployeeRecords employee={employeeId } />
</> </>
); );
} }
@ -76,18 +81,19 @@ const EmployeeProfile = () => {
} }
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
@ -117,109 +123,58 @@ 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"> <h6 className="mb-2 text-muted text-start">Employee Info</h6>
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"> <td className="text-start">{currentEmployee?.email || <em>NA</em>}</td>
{currentEmployee?.email || <em>NA</em>}
</td>
</tr> </tr>
<tr> <tr>
<td className="fw-medium text-start"> <td className="fw-medium text-start">Phone Number:</td>
Phone Number: <td className="text-start">{currentEmployee?.phoneNumber || <em>NA</em>}</td>
</td>
<td className="text-start">
{currentEmployee?.phoneNumber || <em>NA</em>}
</td>
</tr> </tr>
<tr> <tr>
<td className="fw-medium text-start"> <td className="fw-medium text-start">Emergency Contact Person:</td>
Emergency Contact Person: <td className="text-start">{currentEmployee?.emergencyContactPerson || <em>NA</em>}</td>
</td>
<td className="text-start">
{currentEmployee?.emergencyContactPerson || (
<em>NA</em>
)}
</td>
</tr> </tr>
<tr> <tr>
<td className="fw-medium text-start"> <td className="fw-medium text-start">Emergency Contact Number:</td>
Emergency Contact Number: <td className="text-start">{currentEmployee?.emergencyPhoneNumber || <em>NA</em>}</td>
</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"> <td className="text-start">{currentEmployee?.gender || <em>NA</em>}</td>
{currentEmployee?.gender || <em>NA</em>}
</td>
</tr> </tr>
<tr> <tr>
<td className="fw-medium text-start"> <td className="fw-medium text-start">Birth Date:</td>
Birth Date: <td className="text-start">{currentEmployee?.birthDate ? new Date(currentEmployee.birthDate).toLocaleDateString() : <em>NA</em>}</td>
</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"> <td className="fw-medium text-start">Joining Date:</td>
Joining Date: <td className="text-start">{currentEmployee?.joiningDate ? new Date(currentEmployee.joiningDate).toLocaleDateString() : <em>NA</em>}</td>
</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"> <td className="fw-medium text-start">Job Role:</td>
Job Role: <td className="text-start">{currentEmployee?.jobRole || <em>NA</em>}</td>
</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"> <td className="text-start">{currentEmployee?.currentAddress || <em>NA</em>}</td>
{currentEmployee?.currentAddress || <em>NA</em>}
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
<button <button className="btn btn-primary btn-block" onClick={() => navigate(`/employee/manage/${currentEmployee?.id}`)}>
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>
@ -227,13 +182,12 @@ const EmployeeProfile = () => {
<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 <EmployeeNav onPillClick={handlePillClick} activePill={activePill} />
onPillClick={handlePillClick}
activePill={activePill}
/>
</div> </div>
<div className="card"> <div className="card">
<div className="row row-bordered g-0">{renderContent()}</div> <div className="row row-bordered g-0">
{renderContent()}
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -83,7 +83,7 @@ const MasterTable = ({ data, columns, loading, handleModalData }) => {
currentItems.map((item, index) => ( currentItems.map((item, index) => (
<tr key={index}> <tr key={index}>
<td style={{ width: "20px" }}> <td style={{ width: "20px" }}>
<i className="bx bx-right-arrow-alt"></i> <i class="bx bx-right-arrow-alt"></i>
</td> </td>
{updatedColumns.map((col) => ( {updatedColumns.map((col) => (
<td className="text-start mx-2" key={col.key}> <td className="text-start mx-2" key={col.key}>

View File

@ -21,7 +21,8 @@ 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;
} }
} }
@ -36,6 +37,7 @@ axiosClient.interceptors.response.use(
(response) => response, (response) => response,
async (error) => { async (error) => {
const originalRequest = error.config; const originalRequest = error.config;
if (!originalRequest) { if (!originalRequest) {
@ -83,13 +85,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) { if (error.response.status === 401 && !originalRequest._retry) {
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 || error.response.data.errors === "Invalid or expired refresh token.") { if (!refreshToken) {
// 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);
@ -114,6 +116,7 @@ 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);
@ -189,5 +192,5 @@ export const api = {
}; };
//export default axiosClient; //export default axiosClient;
function redirectToLogin() { function redirectToLogin() {
window.location.href = "/auth/login"; // window.location.href = "/auth/login";
} }