Merge branch 'UI_Changes_PMS' of https://git.marcoaiot.com/admin/marco.pms.web into UI_Changes_PMS

This commit is contained in:
pramod mahajan 2025-09-08 11:57:30 +05:30
commit 0194c4427a
20 changed files with 218 additions and 173 deletions

View File

@ -114,7 +114,10 @@ const Attendance = ({ getRole, handleModalData, searchTerm }) => {
return ( return (
<> <>
<div className="table-responsive text-nowrap h-100" > <div
className="table-responsive text-nowrap h-100"
style={{ minHeight: "200px" }} // 🔹 Ensures fixed height
>
<div className="d-flex text-start align-items-center py-2"> <div className="d-flex text-start align-items-center py-2">
<strong>Date : {formatUTCToLocalTime(todayDate)}</strong> <strong>Date : {formatUTCToLocalTime(todayDate)}</strong>
<div className="form-check form-switch text-start m-0 ms-5"> <div className="form-check form-switch text-start m-0 ms-5">
@ -209,7 +212,11 @@ const Attendance = ({ getRole, handleModalData, searchTerm }) => {
</tr> </tr>
))} ))}
{!attendance && ( {!attendance && (
<span className="text-secondary m-4">No employees assigned to the project!</span> <tr>
<td colSpan={6} className="text-center text-secondary" style={{ height: "200px" }}>
No employees assigned to the project!
</td>
</tr>
)} )}
</tbody> </tbody>
</table> </table>
@ -258,7 +265,10 @@ const Attendance = ({ getRole, handleModalData, searchTerm }) => {
)} )}
</> </>
) : ( ) : (
<div className="text-muted my-4"> <div
className="d-flex justify-content-center align-items-center text-muted"
style={{ height: "200px" }}
>
{searchTerm {searchTerm
? "No results found for your search." ? "No results found for your search."
: attendanceList.length === 0 : attendanceList.length === 0

View File

@ -42,7 +42,7 @@ const AttendanceLog = ({ handleModalData, searchTerm }) => {
const [dateRange, setDateRange] = useState({ startDate: "", endDate: "" }); const [dateRange, setDateRange] = useState({ startDate: "", endDate: "" });
const dispatch = useDispatch(); const dispatch = useDispatch();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [showPending,setShowPending] = useState(false) const [showPending, setShowPending] = useState(false)
const [isRefreshing, setIsRefreshing] = useState(false); const [isRefreshing, setIsRefreshing] = useState(false);
const [processedData, setProcessedData] = useState([]); const [processedData, setProcessedData] = useState([]);
@ -245,17 +245,16 @@ const AttendanceLog = ({ handleModalData, searchTerm }) => {
</div> </div>
<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 ${isFetching ? "spin" : ""
isFetching ? "spin" : ""
}`} }`}
title="Refresh" title="Refresh"
onClick={() => refetch()} onClick={() => refetch()}
/> />
</div> </div>
</div> </div>
<div className="table-responsive text-nowrap"> <div className="table-responsive text-nowrap" style={{ minHeight: "200px" }}>
{isLoading ? ( {isLoading ? (
<div> <div className="d-flex justify-content-center align-items-center" style={{ height: "200px" }}>
<p className="text-secondary">Loading...</p> <p className="text-secondary">Loading...</p>
</div> </div>
) : filteredSearchData?.length > 0 ? ( ) : filteredSearchData?.length > 0 ? (
@ -350,8 +349,11 @@ const AttendanceLog = ({ handleModalData, searchTerm }) => {
)} )}
</div> </div>
{paginatedAttendances?.length == 0 && filteredSearchData?.length > 0 && ( {paginatedAttendances?.length == 0 && filteredSearchData?.length > 0 && (
<div className="my-4"> <div
<span className="text-secondary">No Pending Record Available !</span> className="d-flex justify-content-center align-items-center text-secondary"
style={{ height: "200px" }}
>
No Record Available !
</div> </div>
)} )}
{filteredSearchData.length > ITEMS_PER_PAGE && ( {filteredSearchData.length > ITEMS_PER_PAGE && (
@ -369,8 +371,7 @@ const AttendanceLog = ({ handleModalData, searchTerm }) => {
(pageNumber) => ( (pageNumber) => (
<li <li
key={pageNumber} key={pageNumber}
className={`page-item ${ className={`page-item ${currentPage === pageNumber ? "active" : ""
currentPage === pageNumber ? "active" : ""
}`} }`}
> >
<button <button
@ -383,8 +384,7 @@ const AttendanceLog = ({ handleModalData, searchTerm }) => {
) )
)} )}
<li <li
className={`page-item ${ className={`page-item ${currentPage === totalPages ? "disabled" : ""
currentPage === totalPages ? "disabled" : ""
}`} }`}
> >
<button <button

View File

@ -87,9 +87,9 @@ const Regularization = ({ handleRequest, searchTerm }) => {
}, [employeeHandler]); }, [employeeHandler]);
return ( return (
<div className="table-responsive text-nowrap pb-4"> <div className="table-responsive text-nowrap pb-4" style={{ minHeight: "200px" }}>
{loading ? ( {loading ? (
<div className="my-2"> <div className="d-flex justify-content-center align-items-center" style={{ height: "200px" }}>
<p className="text-secondary">Loading...</p> <p className="text-secondary">Loading...</p>
</div> </div>
) : currentItems?.length > 0 ? ( ) : currentItems?.length > 0 ? (
@ -143,9 +143,14 @@ const Regularization = ({ handleRequest, searchTerm }) => {
</tbody> </tbody>
</table> </table>
) : ( ) : (
<div className="my-4"> <div
className="d-flex justify-content-center align-items-center"
style={{ height: "200px" }}
>
<span className="text-secondary"> <span className="text-secondary">
{searchTerm ? "No results found for your search." : "No Requests Found !"} {searchTerm
? "No results found for your search."
: "No Requests Found !"}
</span> </span>
</div> </div>
)} )}
@ -163,8 +168,7 @@ const Regularization = ({ handleRequest, searchTerm }) => {
{[...Array(totalPages)].map((_, index) => ( {[...Array(totalPages)].map((_, index) => (
<li <li
key={index} key={index}
className={`page-item ${ className={`page-item ${currentPage === index + 1 ? "active" : ""
currentPage === index + 1 ? "active" : ""
}`} }`}
> >
<button <button
@ -176,8 +180,7 @@ const Regularization = ({ handleRequest, searchTerm }) => {
</li> </li>
))} ))}
<li <li
className={`page-item ${ className={`page-item ${currentPage === totalPages ? "disabled" : ""
currentPage === totalPages ? "disabled" : ""
}`} }`}
> >
<button <button

View File

@ -105,7 +105,7 @@ const AttendanceOverview = () => {
{/* Header */} {/* Header */}
<div className="d-flex justify-content-between align-items-center mb-3"> <div className="d-flex justify-content-between align-items-center mb-3">
<div className="card-title mb-0 text-start"> <div className="card-title mb-0 text-start">
<h5 className="mb-1">Attendance Overview</h5> <h5 className="mb-1 fw-bold">Attendance Overview</h5>
<p className="card-subtitle">Role-wise present count</p> <p className="card-subtitle">Role-wise present count</p>
</div> </div>
<div className="d-flex gap-2"> <div className="d-flex gap-2">

View File

@ -19,7 +19,7 @@ const ProjectCompletionChart = () => {
<div className="card h-100"> <div className="card h-100">
<div className="card-header d-flex align-items-start justify-content-between"> <div className="card-header d-flex align-items-start justify-content-between">
<div className="card-title mb-0 text-start"> <div className="card-title mb-0 text-start">
<h5 className="mb-1">Projects</h5> <h5 className="mb-1 fw-bold ">Projects</h5>
<p className="card-subtitle">Projects Completion Status</p> <p className="card-subtitle">Projects Completion Status</p>
</div> </div>
</div> </div>

View File

@ -90,7 +90,7 @@ const ProjectProgressChart = ({
<div className="d-flex flex-wrap justify-content-between align-items-start mb-2"> <div className="d-flex flex-wrap justify-content-between align-items-start mb-2">
{/* Left: Title */} {/* Left: Title */}
<div className="card-title text-start"> <div className="card-title text-start">
<h5 className="mb-1">Project Progress</h5> <h5 className="mb-1 fw-bold">Project Progress</h5>
<p className="card-subtitle">Progress Overview by Project</p> <p className="card-subtitle">Progress Overview by Project</p>
</div> </div>
</div> </div>

View File

@ -18,6 +18,7 @@ import {
import { clearApiCacheKey } from "../../slices/apiCacheSlice"; import { clearApiCacheKey } from "../../slices/apiCacheSlice";
import { useMutation } from "@tanstack/react-query"; import { useMutation } from "@tanstack/react-query";
import Label from "../common/Label"; import Label from "../common/Label";
import DatePicker from "../common/DatePicker";
const mobileNumberRegex = /^[0-9]\d{9}$/; const mobileNumberRegex = /^[0-9]\d{9}$/;
@ -371,41 +372,43 @@ const ManageEmployee = ({ employeeId, onClosed, IsAllEmployee }) => {
)} )}
</div> </div>
<div className="col-sm-4"> <div className="col-sm-4">
<Label className="form-text text-start" required>Birth Date</Label> <Label className="form-text text-start" required>
Birth Date
</Label>
<div className="input-group"> <div className="input-group">
<input <DatePicker
className="form-control form-control-sm" name="birthDate"
type="date" control={control} // from useForm()
{...register("birthDate")} placeholder="DD-MM-YYYY"
id="birthDate" maxDate={new Date()} // restrict future dates (e.g., birth date must be today or past)
className="w-100"
/> />
</div> </div>
{errors.birthDate && ( {errors.birthDate && (
<div <div className="danger-text text-start" style={{ fontSize: "12px" }}>
className="danger-text text-start"
style={{ fontSize: "12px" }}
>
{errors.birthDate.message} {errors.birthDate.message}
</div> </div>
)} )}
</div> </div>
<div className="col-sm-4"> <div className="col-sm-4">
<Label className="form-text text-start" required>Joining Date</Label> <Label className="form-text text-start" required>
Joining Date
</Label>
<div className="input-group"> <div className="input-group">
<input <DatePicker
className="form-control form-control-sm" name="joiningDate"
type="date" control={control} // from useForm()
{...register("joiningDate")} placeholder="DD-MM-YYYY"
id="joiningDate" // For joining date, we dont block future dates
className="w-100"
/> />
</div> </div>
{errors.joiningDate && ( {errors.joiningDate && (
<div <div className="danger-text text-start" style={{ fontSize: "12px" }}>
className="danger-text text-start"
style={{ fontSize: "12px" }}
>
{errors.joiningDate.message} {errors.joiningDate.message}
</div> </div>
)} )}

View File

@ -51,13 +51,13 @@ const AboutProject = () => {
)} )}
{projects_Details && ( {projects_Details && (
<> <>
<div className="card mb-6"> <div className="card mb-4">
<div className="card-header text-start"> <div className="card-header text-start">
<h6 className="card-action-title mb-0 ps-1"> <h5 className="card-action-title mb-0 ps-1">
{" "} {" "}
<i className="fa fa-building rounded-circle text-primary"></i> <i className="fa fa-building rounded-circle text-primary"></i>
<span className="ms-2">Project Profile</span> <span className="ms-2 fw-bold">Project Profile</span>
</h6> </h5>
</div> </div>
<div className="card-body"> <div className="card-body">
<ul className="list-unstyled my-3 ps-0"> <ul className="list-unstyled my-3 ps-0">

View File

@ -0,0 +1,19 @@
/* For Webkit browsers (Chrome, Edge, Safari) */
.modal-dialog-scrollable::-webkit-scrollbar {
width: 6px; /* smaller width */
}
.modal-dialog-scrollable::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, 0.3); /* scrollbar color */
border-radius: 10px;
}
.modal-dialog-scrollable::-webkit-scrollbar-track {
background: transparent;
}
/* For Firefox */
.modal-dialog-scrollable {
scrollbar-width: thin; /* shrinks scrollbar */
scrollbar-color: rgba(0, 0, 0, 0.3) transparent;
}

View File

@ -4,6 +4,7 @@ import { useAllEmployees } from "../../hooks/useEmployees";
import useSearch from "../../hooks/useSearch"; import useSearch from "../../hooks/useSearch";
import AssignEmployeeTable from "./AssignEmployeeTable"; import AssignEmployeeTable from "./AssignEmployeeTable";
import showToast from "../../services/toastService"; import showToast from "../../services/toastService";
import "./MapUser.css";
const MapUsers = ({ const MapUsers = ({
projectId, projectId,

View File

@ -93,7 +93,7 @@ const ProjectInfra = ( {data, onDataChange, eachSiteEngineer} ) =>
> >
<button <button
type="button" type="button"
className="link-button link-button-sm m-1 " className="link-button link-button-sm m-1 btn-primary"
onClick={()=>setshowModalBuilding(true)} onClick={()=>setshowModalBuilding(true)}
> >
<i className="bx bx-plus-circle me-2"></i> <i className="bx bx-plus-circle me-2"></i>
@ -101,7 +101,7 @@ const ProjectInfra = ( {data, onDataChange, eachSiteEngineer} ) =>
</button> </button>
<button <button
type="button" type="button"
className="link-button m-1" className="link-button m-1 btn-primary"
onClick={()=>setshowModalFloor(true)} onClick={()=>setshowModalFloor(true)}
> >
<i className="bx bx-plus-circle me-2"></i> <i className="bx bx-plus-circle me-2"></i>
@ -109,7 +109,7 @@ const ProjectInfra = ( {data, onDataChange, eachSiteEngineer} ) =>
</button> </button>
<button <button
type="button" type="button"
className="link-button m-1" className="link-button m-1 btn-primary"
onClick={() => setshowModalWorkArea(true)} onClick={() => setshowModalWorkArea(true)}
> >
<i className="bx bx-plus-circle me-2"></i> <i className="bx bx-plus-circle me-2"></i>
@ -117,7 +117,7 @@ const ProjectInfra = ( {data, onDataChange, eachSiteEngineer} ) =>
</button> </button>
<button <button
type="button" type="button"
className="link-button m-1" className="link-button m-1 btn-primary"
onClick={()=>setshowModalTask(true)} onClick={()=>setshowModalTask(true)}
> >
<i className="bx bx-plus-circle me-2"></i> <i className="bx bx-plus-circle me-2"></i>

View File

@ -167,11 +167,11 @@ const ProjectOverview = ({ project }) => {
return ( return (
<div className="card" style={{ minHeight: "490px" }}> <div className="card" style={{ minHeight: "490px" }}>
<div className="card-header text-start"> <div className="card-header text-start">
<h6 className="card-action-title mb-0"> <h5 className="card-action-title mb-0">
{" "} {" "}
<i className="fa fa-line-chart rounded-circle text-primary"></i> <i className="fa fa-line-chart rounded-circle text-primary"></i>
<span className="ms-2">Project Statistics</span> <span className="ms-2 fw-bold">Project Statistics</span>
</h6> </h5>
</div> </div>
<div className="card-body"> <div className="card-body">
<ul className="list-unstyled m-0 p-0"> <ul className="list-unstyled m-0 p-0">

View File

@ -276,12 +276,13 @@ const EditMaster = ({ master, onClose }) => {
<div className="col-12 text-end"> <div className="col-12 text-end mt-3">
<button <button
type="button" type="button"
className="btn btn-sm btn-label-secondary me-3" className="btn btn-sm btn-label-secondary me-3"
data-bs-dismiss="modal" data-bs-dismiss="modal"
aria-label="Close" aria-label="Close"
onClick={onClose}
> >
Cancel Cancel
</button> </button>

View File

@ -116,17 +116,18 @@ const EditWorkCategory = ({ data, onClose }) => {
</div> </div>
<div className="col-12 text-center"> <div className="col-12 text-center mt-3">
<button type="submit" className="btn btn-sm btn-primary me-3">
{isLoading ? "Please Wait..." : "Submit"}
</button>
<button <button
type="button" type="button"
className="btn btn-sm btn-label-secondary" className="btn btn-sm btn-label-secondary me-3"
onClick={onClose} onClick={onClose}
> >
Cancel Cancel
</button> </button>
<button type="submit" className="btn btn-sm btn-primary">
{isLoading ? "Please Wait..." : "Submit"}
</button>
</div> </div>

View File

@ -86,7 +86,7 @@ const ManagePaymentMode = ({ data = null, onClose }) => {
className="btn btn-sm btn-primary" className="btn btn-sm btn-primary"
disabled={isPending || Updating} disabled={isPending || Updating}
> >
{isPending || Updating? "Please Wait..." : Updating ? "Update" : "Submit"} {isPending || Updating ? "Please Wait..." : Updating ? "Update" : "Submit"}
</button> </button>
</div> </div>

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect, useCallback } from "react"; import React, { useState, useEffect } from "react";
import { import {
cacheData, cacheData,
clearCacheKey, clearCacheKey,
@ -117,7 +117,13 @@ const AttendancePage = () => {
{ label: "Attendance", link: null }, { label: "Attendance", link: null },
]} ]}
></Breadcrumb> ></Breadcrumb>
<div className="nav-align-top nav-tabs-shadow" >
<div className="nav-align-top nav-tabs-shadow">
{/* Tabs */}
<div className="nav-align-top nav-tabs-shadow bg-white border-bottom">
<div className="row align-items-center g-0 mb-3 mb-md-0">
{/* Tabs */}
<div className="col-12 col-md">
<ul className="nav nav-tabs" role="tablist"> <ul className="nav nav-tabs" role="tablist">
<li className="nav-item"> <li className="nav-item">
<button <button
@ -145,7 +151,8 @@ const AttendancePage = () => {
Logs Logs
</button> </button>
</li> </li>
<li className={`nav-item ${!DoRegularized && "d-none"}`}>
<li className={`nav-item ${!DoRegularized ? "d-none" : ""}`}>
<button <button
type="button" type="button"
className={`nav-link ${ className={`nav-link ${
@ -158,19 +165,22 @@ const AttendancePage = () => {
Regularization Regularization
</button> </button>
</li> </li>
</ul>
</div>
{/* 🔹 Search box placed after Regularization tab */} {/* Single search input that moves */}
<li className="nav-item ms-auto me-3"> <div className="col-12 col-md-auto mt-2 mt-md-0 ms-md-auto px-2">
<input <input
type="text" type="text"
className="form-control form-control-sm mt-1" className="form-control form-control-sm"
placeholder="Search Employee..." placeholder="Search Employee..."
value={searchTerm} value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)} onChange={(e) => setSearchTerm(e.target.value)}
style={{ minWidth: "200px" }} style={{ minWidth: "200px" }}
/> />
</li> </div>
</ul> </div>
</div>
<div className="tab-content attedanceTabs py-0 px-1 px-sm-3"> <div className="tab-content attedanceTabs py-0 px-1 px-sm-3">
{selectedProject ? ( {selectedProject ? (

View File

@ -178,7 +178,7 @@ const DailyTask = () => {
</div> </div>
{/* --- Table --- */} {/* --- Table --- */}
<div className="table-responsive text-nowrap mt-3"> <div className="table-responsive text-nowrap mt-3" style={{ minHeight: "200px" }}>
<table className="table"> <table className="table">
<thead> <thead>
<tr> <tr>
@ -193,14 +193,16 @@ const DailyTask = () => {
<tbody> <tbody>
{taskLoading && ( {taskLoading && (
<tr> <tr>
<td colSpan={6} className="text-center"> <td colSpan={6} className="text-center align-middle" style={{ height: "200px" }}>
<Loader/> <Loader />
</td> </td>
</tr> </tr>
)} )}
{!taskLoading && groupedTasks.length === 0 && ( {!taskLoading && groupedTasks.length === 0 && (
<tr> <tr>
<td colSpan={6} className="text-center">No Reports Found</td> <td colSpan={6} className="text-center align-middle" style={{ height: "200px" }}>
No Reports Found
</td>
</tr> </tr>
)} )}
{!taskLoading && {!taskLoading &&
@ -239,6 +241,7 @@ const DailyTask = () => {
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -414,14 +414,11 @@ const EmployeeList = () => {
{/* Add Employee Button */} {/* Add Employee Button */}
{Manage_Employee && ( {Manage_Employee && (
<button <button
className="btn btn-sm btn-primary" className="p-1 me-1 m-sm-0 bg-primary rounded-circle"
type="button" type="button"
onClick={() => handleEmployeeModel(null)} onClick={() => handleEmployeeModel(null)}
> >
<i className="bx bx-plus-circle me-2"></i> <i className="bx bx-plus fs-4 text-white"></i>
<span className="d-none d-md-inline-block">
Add New Employee
</span>
</button> </button>
)} )}
</div> </div>
@ -636,7 +633,7 @@ const EmployeeList = () => {
} }
className="dropdown-item py-1" className="dropdown-item py-1"
> >
<i className="bx bx-detail bx-sm"></i> View <i className="bx bx-show text-primary bx-sm"></i> View
</button> </button>
{/* If ACTIVE employee */} {/* If ACTIVE employee */}
@ -648,8 +645,7 @@ const EmployeeList = () => {
handleEmployeeModel(item.id) handleEmployeeModel(item.id)
} }
> >
<i className="bx bx-edit bx-sm"></i>{" "} <i className="bx bx-edit text-secondary bx-sm"></i> Edit
Edit
</button> </button>
{/* Suspend only when active */} {/* Suspend only when active */}
@ -658,8 +654,7 @@ const EmployeeList = () => {
className="dropdown-item py-1" className="dropdown-item py-1"
onClick={() => handleOpenDelete(item)} onClick={() => handleOpenDelete(item)}
> >
<i className="bx bx-task-x bx-sm"></i>{" "} <i className="bx bx-task-x text-danger bx-sm"></i> Suspend
Suspend
</button> </button>
)} )}
@ -684,8 +679,7 @@ const EmployeeList = () => {
className="dropdown-item py-1" className="dropdown-item py-1"
onClick={() => handleOpenDelete(item)} onClick={() => handleOpenDelete(item)}
> >
<i className="bx bx-refresh bx-sm me-1"></i>{" "} <i className="bx bx-refresh text-danger bx-sm me-0"></i> Re-activate
Re-activate
</button> </button>
)} )}
</div> </div>

View File

@ -163,7 +163,7 @@ useEffect(() => {
name="DataTables_Table_0_length" name="DataTables_Table_0_length"
aria-controls="DataTables_Table_0" aria-controls="DataTables_Table_0"
className="form-select py-1 px-2" className="form-select py-1 px-2"
style={{ fontSize: "0.875rem", height: "32px", width: "150px" }} style={{ fontSize: "0.875rem", height: "32px", width: "170px" }}
value={selectedMaster} value={selectedMaster}
> >
{isLoading && ( {isLoading && (

View File

@ -83,7 +83,7 @@ const ProjectDetails = () => {
return ( return (
<> <>
<div className="row"> <div className="row">
<div className="col-lg-4 col-md-5 mt-5"> <div className="col-lg-4 col-md-5 mt-2">
<AboutProject></AboutProject> <AboutProject></AboutProject>
<ProjectOverview project={projectId} /> <ProjectOverview project={projectId} />
</div> </div>