Compare commits

...

26 Commits

Author SHA1 Message Date
284d36e5ac Merge pull request 'Added logic to the employee list to hide the 'Manage Role' and 'Suspend' buttons for system-defined employees' (#85) from Ashutosh_Enhancement#198_Added_IsSystem into Issue_May_2W
Reviewed-on: #85
2025-05-08 10:15:33 +00:00
ba763f986d Added logic to the employee list to hide the 'Manage Role' and 'Suspend' buttons for system-defined employees 2025-05-08 10:15:33 +00:00
e856220173 Merge pull request 'restrict employee search to first and last name fields only' (#81) from pramod_Bug#150 into Issue_May_2W
Reviewed-on: #81
2025-05-08 10:15:07 +00:00
Pramod Mahajan
9ac15d3cf7 restrict employee search to first and last name fields only 2025-05-08 10:15:07 +00:00
9a885c2b72 Merge pull request 'handled server negative response, in user readable format' (#84) from pramod_Bug-#163 into Issue_May_2W
Reviewed-on: #84
2025-05-08 10:14:54 +00:00
Pramod Mahajan
3161288871 handled server negative response, in user readable format 2025-05-08 10:14:54 +00:00
2242569e48 Merge pull request 'project list or card will display 10 per page.' (#83) from pramod_Feature-#51 into Issue_May_2W
Reviewed-on: #83
2025-05-08 10:14:02 +00:00
Pramod Mahajan
7fa502f44c project list or card will display 10 per page. 2025-05-08 10:14:02 +00:00
1ae1a45cb1 Merge pull request 'showing custom delete confirmation modal in master module until API is ready' (#82) from pramod_Bug#141 into Issue_May_2W
Reviewed-on: #82
2025-05-08 10:13:49 +00:00
Pramod Mahajan
4175fb67c6 showing custom delete confirmation modal in master module until API is ready 2025-05-08 10:13:49 +00:00
670efbe1bf Merge pull request 'Reset Select Activity field and remove used activity after task submission' (#80) from pramod_Bug#171 into Issue_May_2W
Reviewed-on: #80
2025-05-08 10:13:19 +00:00
Pramod Mahajan
865cc7a366 Reset Select Activity field and remove used activity after task submission 2025-05-08 10:13:19 +00:00
4fe09330c1 Merge pull request 'added va;idation for contact person. it will accept only alphabetical character' (#79) from pramod_Bug#197 into Issue_May_2W
Reviewed-on: #79
2025-05-08 10:12:23 +00:00
Pramod Mahajan
b004fe8c15 added va;idation for contact person. it will accept only alphabetical character 2025-05-08 10:12:23 +00:00
505c9a46db Merge pull request 'added form submission logic with loading state management' (#78) from pramod_Bug#196 into Issue_May_2W
Reviewed-on: #78
2025-05-08 05:39:24 +00:00
Pramod Mahajan
6c4c6db0d7 added form submission logic with loading state management 2025-05-08 05:39:24 +00:00
d81482583e Merge pull request 'status filter dropdown available for both view card and list' (#77) from pramod_Bug#195 into Issue_May_2W
Reviewed-on: #77
2025-05-08 05:38:44 +00:00
Pramod Mahajan
6c9fd4d20a status filter dropdown available for both view card and list 2025-05-08 05:38:44 +00:00
ddf9e86235 Merge pull request 'Added a toggle switch in the Employee List module to view active and inactive employees separately.' (#76) from Ashutosh_Enhancement#172_Show_InactiveEmployees into Issue_May_2W
Reviewed-on: #76
2025-05-08 05:38:27 +00:00
a3867dfb2f Added a toggle switch in the Employee List module to view active and inactive employees separately. 2025-05-08 05:38:27 +00:00
0180793456 Merge pull request 'dcrease table row size' (#75) from pramod_bug#173TableRowHeight into Issue_May_2W
Reviewed-on: #75
2025-05-08 05:37:33 +00:00
Pramod Mahajan
4f9d2f091a dcrease table row size 2025-05-08 05:37:33 +00:00
5fa7d563f9 Merge pull request 'hide relase date column when active employee and modified column name of role to project role' (#74) from pramod_Bug#189 into Issue_May_2W
Reviewed-on: #74
2025-05-08 05:37:06 +00:00
Pramod Mahajan
8a1cbebced hide relase date coumen when active employee and modified column name of role to project role 2025-05-07 18:54:53 +05:30
ef2fdf899c Merge branch 'pramod_Task#186DeleteActivity' into Issue_May_2W
# Conflicts:
#	src/data/menuData.json
2025-05-07 17:31:50 +05:30
e61ba5b53a remove unused menus 2025-05-07 17:29:58 +05:30
15 changed files with 155 additions and 82 deletions

View File

@ -194,7 +194,8 @@ const ManageEmployee = () => {
navigation("/employees");
})
.catch((error) => {
showToast(error.message, "error");
const message = error?.response?.data?.message || error?.message || "Error occured during api calling"
showToast(message, "error");
setLoading(false);
});
};

View File

@ -157,9 +157,9 @@ const ManageRole = ( {employeeId, onClosed} ) =>
reset();
onClosed();
})
.catch((err) => {
console.error(err);
showToast(err.message, "error");
.catch((error) => {
const message = error?.response?.data?.message || error?.message || "Error occured during api calling"
showToast(message, "error");
setIsLoading(false);
});
};

View File

@ -110,6 +110,7 @@ const TaskModel = ({
await onSubmit(data);
setValue("plannedWork", 0);
setValue( "completedWork", 0 );
setValue("activityID",0)
setIsSubmitting(false);
};
@ -246,7 +247,7 @@ const TaskModel = ({
{selectedWorkArea && (
<div className="col-12 col-md-12">
<label className="form-label" htmlFor="activityID">
<label className="form-label" >
Select Activity
</label>
<select

View File

@ -28,7 +28,10 @@ const ManageProjectInfo = ({ project, handleSubmitForm, onClose }) => {
name: z.string().min(1, { message: "Project Name is required" }),
contactPerson: z
.string()
.min(1, { message: "Contact Person Name is required" }),
.min( 1, {message: "Contact Person Name is required"} )
.regex(/^[A-Za-z\s]+$/, {
message: "Contact Person must contain only letters",
}),
projectAddress: z
.string()
.min(1, { message: "Address is required" })
@ -98,12 +101,13 @@ const ManageProjectInfo = ({ project, handleSubmitForm, onClose }) => {
const onSubmitForm = (updatedProject) => {
setLoading(true);
handleSubmitForm(updatedProject);
handleSubmitForm( updatedProject ,setLoading);
};
useEffect(() => {
return () => setLoading(false);
}, []);
return (
<div
@ -155,6 +159,7 @@ const ManageProjectInfo = ({ project, handleSubmitForm, onClose }) => {
name="contactPerson"
className="form-control"
placeholder="Contact Person"
maxLength={50}
{...register("contactPerson")}
/>
{errors.contactPerson && (
@ -269,8 +274,8 @@ const ManageProjectInfo = ({ project, handleSubmitForm, onClose }) => {
)}
</div>
<div className="col-12 text-center">
<button type="submit" className="btn btn-sm btn-primary me-3">
{isloading ? "Please Wait" : project?.id ? "Update" : "Submit"}
<button type="submit" className="btn btn-sm btn-primary me-3" disabled={isloading}>
{isloading ? "Please Wait..." : project?.id ? "Update" : "Submit"}
</button>
<button
type="button"

View File

@ -21,7 +21,7 @@ const ProjectBanner = ( {project_data} ) =>
const handleShow = () => setShowModal(true);
const handleClose = () => setShowModal(false);
const handleFormSubmit = ( updatedProject ) =>
const handleFormSubmit = ( updatedProject,setLoading ) =>
{
if ( CurrentProject?.id )
@ -51,7 +51,7 @@ const ProjectBanner = ( {project_data} ) =>
}
showToast( "Project updated successfully.", "success" );
setLoading(false)
setShowModal(false)
})
.catch((error) => {

View File

@ -6,3 +6,6 @@
td {
padding: 0.182rem;
}
.table > :not(caption) > * > * {
padding: 0.1rem !important;
}

View File

@ -24,7 +24,8 @@ const Teams = ({ project }) => {
const [filteredEmployees, setFilteredEmployees] = useState([]);
const [removingEmployeeId, setRemovingEmployeeId] = useState(null);
const [assignedLoading, setAssignedLoading] = useState(false);
const [employeeLodaing, setEmployeeLoading] = useState(false);
const [ employeeLodaing, setEmployeeLoading ] = useState( false );
const [activeEmployee,setActiveEmployee] = useState(true)
const navigate = useNavigate();
@ -129,10 +130,13 @@ const Teams = ({ project }) => {
const handleFilterEmployee = (e) => {
const filterValue = e.target.value;
if (filterValue === "true") {
if ( filterValue === "true" )
{
setActiveEmployee(true)
setFilteredEmployees(employees.filter((emp) => emp.isActive));
} else {
setFilteredEmployees(employees.filter((emp) => !emp.isActive));
setFilteredEmployees( employees.filter( ( emp ) => !emp.isActive ) );
setActiveEmployee(false)
}
};
@ -200,8 +204,8 @@ const Teams = ({ project }) => {
<tr>
<th>Name</th>
<th>Assigned Date</th>
<th>Release Date</th>
<th>Role</th>
{!activeEmployee && <th>Release Date</th>}
<th>Project Role</th>
<th>Actions</th>
</tr>
</thead>
@ -236,13 +240,13 @@ const Teams = ({ project }) => {
"DD-MMM-YYYY"
)}{" "}
</td>
<td>
{!activeEmployee && <td>
{item.reAllocationDate
? moment(item.reAllocationDate).format(
"DD-MMM-YYYY"
)
: "Present"}
</td>
</td>}
<td>
<span className="badge bg-label-primary me-1">
{getRole(item.jobRoleId)}

View File

@ -1,4 +1,4 @@
import React from "react";
import React, { useState, useEffect } from "react";
import CreateRole from "./CreateRole";
import DeleteMaster from "./DeleteMaster";
@ -7,8 +7,41 @@ import CreateJobRole from "./CreateJobRole";
import EditJobRole from "./EditJobRole";
import CreateActivity from "./CreateActivity";
import EditActivity from "./EditActivity";
import ConfirmModal from "../common/ConfirmModal";
const MasterModal = ({ modaldata, closeModal }) => {
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
useEffect(() => {
if (modaldata?.modalType === "delete") {
setIsDeleteModalOpen(true);
}
}, [modaldata]);
const handleCloseDeleteModal = () => {
setIsDeleteModalOpen(false);
closeModal();
};
if (modaldata?.modalType === "delete" && isDeleteModalOpen) {
return (
<div
className="modal fade show"
tabIndex="-1"
role="dialog"
style={{ display: "block", backgroundColor: "rgba(0,0,0,0.5)" }}
aria-hidden="false"
>
<ConfirmModal
type="delete"
header={`Delete ${modaldata.masterType}`}
message={"comming soon.."}
onClose={handleCloseDeleteModal}
/>
</div>
);
}
return (
<div
className="modal fade"
@ -20,9 +53,7 @@ const MasterModal = ({ modaldata, closeModal }) => {
>
<div
className={`modal-dialog mx-sm-auto mx-1 ${
["Application Role", "Edit-Application Role"].includes(
modaldata?.modalType
)
["Application Role", "Edit-Application Role"].includes(modaldata?.modalType)
? "modal-lg"
: "modal-md"
} modal-simple`}
@ -36,33 +67,24 @@ const MasterModal = ({ modaldata, closeModal }) => {
aria-label="Close"
onClick={closeModal}
></button>
<div className="text-center mb-2"></div>
{modaldata?.modalType === "Application Role" && (
<CreateRole
masmodalType={modaldata.masterType}
onClose={closeModal}
/>
{modaldata.modalType === "Application Role" && (
<CreateRole masmodalType={modaldata.masterType} onClose={closeModal} />
)}
{modaldata?.modalType === "Edit-Application Role" && (
{modaldata.modalType === "Edit-Application Role" && (
<EditRole master={modaldata} onClose={closeModal} />
)}
{modaldata?.modalType === "delete" && (
<DeleteMaster master={modaldata} onClose={closeModal} />
)}
{modaldata?.modalType === "Job Role" && (
{modaldata.modalType === "Job Role" && (
<CreateJobRole onClose={closeModal} />
)}
{modaldata?.modalType === "Edit-Job Role" && (
{modaldata.modalType === "Edit-Job Role" && (
<EditJobRole data={modaldata.item} onClose={closeModal} />
)}
{modaldata?.modalType === "Activity" && (
{modaldata.modalType === "Activity" && (
<CreateActivity onClose={closeModal} />
)}
{modaldata?.modalType === "Edit-Activity" && (
<EditActivity
activityData={modaldata.item}
onClose={closeModal}
/>
{modaldata.modalType === "Edit-Activity" && (
<EditActivity activityData={modaldata.item} onClose={closeModal} />
)}
</div>
</div>

View File

@ -24,13 +24,11 @@
"available": true,
"link": "/employees"
},
{
"text": "Project Status",
"text": "Directory",
"available": true,
"link": "#"
"link": "/directory"
}
]
},
{
@ -67,7 +65,7 @@
{
"text": "Daily Expenses",
"available": true,
"link": "/dashboard/"
"link": "/activities/gallary"
}
]
},

View File

@ -16,7 +16,7 @@ export const useAllEmployees = () => {
setLoading(true);
const response = await EmployeeRepository.getAllEmployeeList();
cacheData("AllEmployees", response.data);
setEmployeeList( response.data );
setEmployeeList(response.data);
setLoading(false);
} else {
setEmployeeList(EmployeeList_cached);
@ -137,15 +137,14 @@ export const useEmployeesByProject = (projectId) => {
return { employees, loading, error, recallProjectEmplloyee: fetchData };
};
export const useEmployeesAllOrByProjectId = (projectId) => {
export const useEmployeesAllOrByProjectId = (projectId, showInactive) => {
const [employees, setEmployees] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const fetchData = async () => {
const fetchData = async (showInactive) => {
if (projectId) {
const Employees_cache = getCachedData("employeeListByProject");
if (!Employees_cache || Employees_cache.projectId !== projectId) {
setLoading(true);
setError(null);
@ -168,30 +167,35 @@ export const useEmployeesAllOrByProjectId = (projectId) => {
setLoading(false);
}
} else {
const employeesCache = getCachedData("allEmployeeList");
const cacheKey = showInactive
? "allInactiveEmployeeList"
: "allEmployeeList";
const employeesCache = getCachedData(cacheKey);
if (!employeesCache) {
if (employeesCache) {
setEmployees(employeesCache.data);
setLoading(false);
} else {
setLoading(true);
setError(null);
try {
const response = await EmployeeRepository.getAllEmployeeList();
const response = await EmployeeRepository.getAllEmployeeList(
showInactive
);
setEmployees(response.data);
cacheData("allEmployeeList", { data: response.data });
cacheData(cacheKey, { data: response.data });
setLoading(false);
} catch (err) {
setError("Failed to fetch data.");
setLoading(false);
}
} else {
setEmployees(employeesCache.data);
setLoading(false);
}
}
};
useEffect(() => {
fetchData(); // Fetch data when the component mounts or projectId changes
fetchData(showInactive); // Fetch data when the component mounts or projectId changes
}, [projectId]); // Re-fetch when projectId changes
return {

View File

@ -13,7 +13,7 @@ const Directory = () => {
<Breadcrumb
data={[
{ label: "Home", link: "/dashboard" },
{ label: "Directory", link: null },
{ label: "Directory (Comming Soon)", link: null },
]}
></Breadcrumb>
@ -126,7 +126,7 @@ const Directory = () => {
<tbody className="table-border-bottom-0 overflow-auto ">
<tr>
<td colSpan="12" className="text-center py-4">
No projects found
comming soon....
</td>
</tr>
</tbody>

View File

@ -25,10 +25,11 @@ const EmployeeList = () => {
const { profile: loginUser } = useProfile();
const [selectedProject, setSelectedProject] = useState("");
const { projects, loading: projectLoading } = useProjects();
const [showInactive, setShowInactive] = useState(false);
const ManageEmployee = useHasUserPermission(MANAGE_EMPLOYEES);
const { employees, loading, setLoading, error, recallEmployeeData } =
useEmployeesAllOrByProjectId(selectedProject);
useEmployeesAllOrByProjectId(selectedProject,showInactive);
const [projectsList, setProjectsList] = useState(projects || []);
const [employeeList, setEmployeeList] = useState([]);
@ -48,11 +49,10 @@ const EmployeeList = () => {
if (!employeeList.length) return;
const results = employeeList.filter((item) =>
Object.values(item).some(
(field) => field && field.toString().toLowerCase().includes(value)
)
);
const results = employeeList.filter((item) => {
const fullName = `${item.firstName} ${item.lastName}`.toLowerCase();
return fullName.includes(value);
});
setFilteredData(results);
};
@ -109,9 +109,10 @@ const EmployeeList = () => {
showToast("Employee deleted successfully.", "success");
clearCacheKey("employeeListByProject");
clearCacheKey("allEmployeeList");
clearCacheKey("allInactiveEmployeeList");
clearCacheKey("employeeProfile");
setEmployeeList([]);
recallEmployeeData();
recallEmployeeData(showInactive);
})
.catch((error) => {
const message =
@ -154,6 +155,12 @@ const EmployeeList = () => {
}
};
const handleToggle = (e) => {
setShowInactive(e.target.checked);
recallEmployeeData(e.target.checked);
};
return (
<>
{isCreateModalOpen && (
@ -317,6 +324,25 @@ const EmployeeList = () => {
</div>
</div>
</div>
<div className="text-end mb-2">
<label class="switch switch-primary">
<input
type="checkbox"
class="switch-input"
checked={showInactive}
onChange={handleToggle}
/>
<span class="switch-toggle-slider">
<span class="switch-on">
<i class="icon-base bx bx-check"></i>
</span>
<span class="switch-off">
<i class="icon-base bx bx-x"></i>
</span>
</span>
<span class="switch-label">Show Inactive Employees</span>
</label>
</div>
<table
className="datatables-users table border-top dataTable no-footer dtr-column text-nowrap"
id="DataTables_Table_0"
@ -448,7 +474,9 @@ const EmployeeList = () => {
<div className="d-flex flex-column">
<a
onClick={() =>
navigate(`/employee/${item.id}?for=attendance`)
navigate(
`/employee/${item.id}?for=attendance`
)
}
className="text-heading text-truncate cursor-pointer"
>
@ -490,12 +518,19 @@ const EmployeeList = () => {
{moment(item.joiningDate).format("DD-MMM-YYYY")}
</td>
<td>
{showInactive ? <span
className="badge bg-label-danger"
text-capitalized=""
>
Inactive
</span>
:
<span
className="badge bg-label-success"
text-capitalized=""
>
Active
</span>
</span>}
</td>
{ManageEmployee && (
<td className="text-end">
@ -521,7 +556,7 @@ const EmployeeList = () => {
>
<i className="bx bx-edit bx-sm"></i> Edit
</Link>
<button
{!item.isSystem && (<><button
className="dropdown-item py-1"
onClick={() => suspendEmployee(item.id)}
>
@ -537,7 +572,7 @@ const EmployeeList = () => {
>
<i className="bx bx-cog bx-sm"></i> Manage
Role
</button>
</button></>)}
</div>
</div>
</td>

View File

@ -25,7 +25,7 @@ const ProjectList = () => {
const dispatch = useDispatch();
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage] = useState(6);
const [itemsPerPage] = useState(10);
const [searchTerm, setSearchTerm] = useState("");
const [selectedStatuses, setSelectedStatuses] = useState([
"b74da4c2-d07e-46f2-9919-e75e49b12731",
@ -193,7 +193,7 @@ const ProjectList = () => {
<i className="bx bx-list-ul bx-sm"></i>
</button>
</div>
{!listView && (
<div className="dropdown ms-3">
<a
className="dropdown-toggle hide-arrow cursor-pointer"
@ -235,7 +235,7 @@ const ProjectList = () => {
))}
</ul>
</div>
)}
</div>
<div>

View File

@ -1,7 +1,7 @@
import { api } from "../utils/axiosClient";
const EmployeeRepository = {
getAllEmployeeList:()=>api.get(`api/employee/list`),
getAllEmployeeList:(showInactive)=>api.get(`api/employee/list?showInactive=${showInactive}`),
getEmployeeListByproject: (projectid) =>
api.get(`/api/employee/list/${projectid}`),
searchEmployees: (query) =>

View File

@ -15,7 +15,7 @@ export const RolesRepository = {
getEmployeeRoles:(id)=>api.get(`/api/employee/roles/${id}`),
createEmployeeRoles:(data)=>api.post("/api/employee/roles",data)
createEmployeeRoles:(data)=>api.post("/api/roles/assign-roles",data)
};