implemented singlR

This commit is contained in:
pramod.mahajan 2025-10-01 13:00:38 +05:30
parent ae772d925a
commit 2aae7194b7
18 changed files with 628 additions and 658 deletions

View File

@ -189,12 +189,12 @@ const DocumentFilterPanel = ({ entityTypeId, onApply }) => {
<div className="d-flex justify-content-end py-3 gap-2"> <div className="d-flex justify-content-end py-3 gap-2">
<button <button
type="button" type="button"
className="btn btn-label-secondary btn-xs" className="btn btn-label-secondary btn-sm"
onClick={onClear} onClick={onClear}
> >
Clear Clear
</button> </button>
<button type="submit" className="btn btn-primary btn-xs"> <button type="submit" className="btn btn-primary btn-sm">
Apply Apply
</button> </button>
</div> </div>

View File

@ -17,9 +17,8 @@ const SkeletonCell = ({
/> />
); );
export const DocumentTableSkeleton = ({ rows = 5 }) => { export const DocumentTableSkeleton = ({ rows = 10 }) => {
return ( return (
<table className="card-body table border-top dataTable no-footer dtr-column text-nowrap"> <table className="card-body table border-top dataTable no-footer dtr-column text-nowrap">
<thead> <thead>
<tr> <tr>
@ -47,7 +46,11 @@ export const DocumentTableSkeleton = ({ rows = 5 }) => {
{/* Uploaded By (Avatar + Name) */} {/* Uploaded By (Avatar + Name) */}
<td className="text-start"> <td className="text-start">
<div className="d-flex align-items-center gap-2"> <div className="d-flex align-items-center gap-2">
<SkeletonCell width="30px" height={30} className="rounded-circle" /> <SkeletonCell
width="30px"
height={30}
className="rounded-circle"
/>
<SkeletonCell width="80px" height={16} /> <SkeletonCell width="80px" height={16} />
</div> </div>
</td> </td>
@ -65,6 +68,5 @@ export const DocumentTableSkeleton = ({ rows = 5 }) => {
))} ))}
</tbody> </tbody>
</table> </table>
); );
}; };

View File

@ -117,7 +117,7 @@ const Documents = ({ Document_Entity, Entity }) => {
}, [Document_Entity]); }, [Document_Entity]);
return ( return (
<DocumentContext.Provider value={contextValues}> <DocumentContext.Provider value={contextValues}>
<div className="mt-5"> <div className="mt-2">
<div className="card page-min-h d-flex p-2"> <div className="card page-min-h d-flex p-2">
<div className="row align-items-center"> <div className="row align-items-center">
{/* Search */} {/* Search */}

View File

@ -82,9 +82,9 @@ const DocumentsList = ({
if (isLoading || isFetching) return <DocumentTableSkeleton />; if (isLoading || isFetching) return <DocumentTableSkeleton />;
if (isError) if (isError)
return <div>Error: {error?.message || "Something went wrong"}</div>; return <div>Error: {error?.message || "Something went wrong"}</div>;
if (isInitialEmpty) return <div>No documents found yet.</div>; if (isInitialEmpty) return <div className="py-12 my-12">No documents found yet.</div>;
if (isSearchEmpty) return <div>No results found for "{debouncedSearch}"</div>; if (isSearchEmpty) return <div className="py-12 my-12">No results found for "{debouncedSearch}"</div>;
if (isFilterEmpty) return <div>No documents match your filter.</div>; if (isFilterEmpty) return <div className="py-12 my-12">No documents match your filter.</div>;
const handleDelete = () => { const handleDelete = () => {
ActiveInActive( ActiveInActive(
@ -180,10 +180,10 @@ const DocumentsList = ({
/> />
)} )}
<div className="table-responsive"> <div className="table-responsive p-2">
<table className="table border-top dataTable text-nowrap"> <table className="table border-top dataTable text-nowrap">
<thead> <thead className="">
<tr className="shadow-sm"> <tr className="py-2 ">
{DocumentColumns.map((col) => ( {DocumentColumns.map((col) => (
<th key={col.key} className={`sorting ${col.align}`}> <th key={col.key} className={`sorting ${col.align}`}>
{col.label} {col.label}

View File

@ -131,7 +131,7 @@ const EmpAttendance = ({ employee }) => {
<AttendLogs Id={attendanceId} /> <AttendLogs Id={attendanceId} />
</GlobalModel> </GlobalModel>
)} )}
<div className="card px-4 mt-5 py-2 " style={{ minHeight: "500px" }}> <div className="card px-4 mt-2 py-2 page-min-h ">
<div <div
className="dataTables_length text-start py-2 d-flex justify-content-between " className="dataTables_length text-start py-2 d-flex justify-content-between "
id="DataTables_Table_0_length" id="DataTables_Table_0_length"

View File

@ -12,11 +12,11 @@ const EmpDashboard = ({ profile }) => {
return ( return (
<> <>
<div className="row"> <div className="row">
<div className="col-12 col-sm-6 pt-5"> <div className="col-12 col-sm-6 pt-2">
{" "} {" "}
<EmpOverview profile={profile}></EmpOverview> <EmpOverview profile={profile}></EmpOverview>
</div> </div>
<div className="col col-sm-6 pt-5"> {/* <div className="col col-sm-6 pt-5">
<div className="card "> <div className="card ">
<div className="card-body"> <div className="card-body">
<small className="card-text text-uppercase text-body-secondary small text-start d-block"> <small className="card-text text-uppercase text-body-secondary small text-start d-block">
@ -29,7 +29,6 @@ const EmpDashboard = ({ profile }) => {
className="d-flex mb-4 align-items-start flex-wrap" className="d-flex mb-4 align-items-start flex-wrap"
key={project.id} key={project.id}
> >
{/* Project Info */}
<div className="flex-grow-1"> <div className="flex-grow-1">
<div className="d-flex flex-wrap align-items-center justify-content-between gap-2"> <div className="d-flex flex-wrap align-items-center justify-content-between gap-2">
<div className="d-flex"> <div className="d-flex">
@ -70,7 +69,6 @@ const EmpDashboard = ({ profile }) => {
</div> </div>
</div> </div>
{/* Dates */}
</div> </div>
</li> </li>
@ -79,7 +77,7 @@ const EmpDashboard = ({ profile }) => {
</div> </div>
</div> </div>
</div> </div> */}
</div> </div>
</> </>
); );

View File

@ -24,7 +24,7 @@ const EmployeeNav = ({ onPillClick, activePill }) => {
icon: "bx bx-file", icon: "bx bx-file",
label: "Documents", label: "Documents",
}, },
{ key: "activities", icon: "bx bx-grid-alt", label: "Activities" }, // { key: "activities", icon: "bx bx-grid-alt", label: "Activities" },
].filter(Boolean); ].filter(Boolean);
return ( return (
<div className="col-md-12"> <div className="col-md-12">

View File

@ -45,8 +45,9 @@ const Header = () => {
pathname pathname
); );
const isExpensePage = /^\/expenses$/.test(pathname); const isExpensePage = /^\/expenses$/.test(pathname);
const isEmployeePage = /^\/employees$/.test(pathname)
return !(isDirectoryPath || isProfilePage || isExpensePage); return !(isDirectoryPath || isProfilePage || isExpensePage || isEmployeePage);
}; };
const allowedProjectStatusIds = [ const allowedProjectStatusIds = [
"603e994b-a27f-4e5d-a251-f3d69b0498ba", "603e994b-a27f-4e5d-a251-f3d69b0498ba",
@ -83,7 +84,7 @@ const Header = () => {
currentProjectDisplayName = projectNames[0].name; currentProjectDisplayName = projectNames[0].name;
} else { } else {
if (selectedProject === null) { if (selectedProject === null) {
currentProjectDisplayName = "All Projects"; currentProjectDisplayName = projectNames[0].name;
} else { } else {
const selectedProjectObj = projectNames.find( const selectedProjectObj = projectNames.find(
(p) => p?.id === selectedProject (p) => p?.id === selectedProject
@ -135,14 +136,14 @@ const Header = () => {
const newProjectHandler = useCallback( const newProjectHandler = useCallback(
async (msg) => { async (msg) => {
if (HasManageProjectPermission && msg.keyword === "Create_Project") { if ( msg.keyword === "Create_Project") {
await fetchData(); await fetchData();
} else if (projectNames?.some((item) => item.id === msg.response.id)) { } else if (projectNames?.some((item) => item.id === msg.response.id)) {
await fetchData(); await fetchData();
} }
cacheData("hasReceived", false); cacheData("hasReceived", false);
}, },
[HasManageProjectPermission, projectNames, fetchData] [ projectNames, fetchData]
); );
useEffect(() => { useEffect(() => {
@ -212,7 +213,7 @@ const Header = () => {
className="dropdown-menu" className="dropdown-menu"
style={{ overflow: "auto", maxHeight: "300px" }} style={{ overflow: "auto", maxHeight: "300px" }}
> >
{isDashboardPath && ( {isProjectPath && (
<li> <li>
<button <button
className="dropdown-item" className="dropdown-item"

View File

@ -66,7 +66,7 @@ const ProjectCard = ({ project }) => {
</div> </div>
</div> </div>
</div> </div>
<div className={`ms-auto ${!ManageProject && "d-none"}`}> <div className={`ms-auto `}>
<div className="dropdown z-2"> <div className="dropdown z-2">
<button <button
type="button" type="button"
@ -106,12 +106,6 @@ const ProjectCard = ({ project }) => {
<span className="align-left">Modify</span> <span className="align-left">Modify</span>
</a> </a>
</li> </li>
<li onClick={handleViewActivities}>
<a className="dropdown-item">
<i className="bx bx-task me-2"></i>
<span className="align-left">Activities</span>
</a>
</li>
</ul> </ul>
</div> </div>
</div> </div>

View File

@ -1,28 +1,20 @@
import React from 'react' import React from "react";
import { useProjects } from '../../hooks/useProjects' import { useProjects } from "../../hooks/useProjects";
import Loader from '../common/Loader' import Loader from "../common/Loader";
import ProjectCard from './ProjectCard' import ProjectCard from "./ProjectCard";
const ProjectCardView = ({currentItems,setCurrentPage,totalPages }) => {
const ProjectCardView = ({ currentItems, setCurrentPage, totalPages }) => {
return ( return (
<div className="row page-min-h"> <div className="row page-min-h">
{currentItems.length === 0 && (
{ currentItems.length === 0 && (
<p className="text-center text-muted">No projects found.</p> <p className="text-center text-muted">No projects found.</p>
)} )}
{currentItems.map((project) => ( {currentItems.map((project) => (
<ProjectCard <ProjectCard key={project.id} project={project} />
key={project.id}
project={project}
/>
))} ))}
{totalPages > 1 && (
{ totalPages > 1 && (
<nav> <nav>
<ul className="pagination pagination-sm justify-content-end py-2"> <ul className="pagination pagination-sm justify-content-end py-2">
<li className={`page-item ${currentPage === 1 && "disabled"}`}> <li className={`page-item ${currentPage === 1 && "disabled"}`}>
@ -47,7 +39,8 @@ const ProjectCardView = ({currentItems,setCurrentPage,totalPages }) => {
</li> </li>
))} ))}
<li <li
className={`page-item ${currentPage === totalPages && "disabled" className={`page-item ${
currentPage === totalPages && "disabled"
}`} }`}
> >
<button <button
@ -63,8 +56,7 @@ const ProjectCardView = ({currentItems,setCurrentPage,totalPages }) => {
</nav> </nav>
)} )}
</div> </div>
);
};
) export default ProjectCardView;
}
export default ProjectCardView

View File

@ -26,9 +26,8 @@ const ProjectListView = ({
const navigate = useNavigate(); const navigate = useNavigate();
const { setMangeProject } = useProjectContext(); const { setMangeProject } = useProjectContext();
// const { data, isLoading, isError, error } = useProjects(); // const { data, isLoading, isError, error } = useProjects();
// check Permissions // check Permissions
const canManageProject = useHasUserPermission(MANAGE_PROJECT); // const canManageProject = useHasUserPermission(MANAGE_PROJECT);
const projectColumns = [ const projectColumns = [
{ {
@ -125,11 +124,15 @@ const ProjectListView = ({
}, },
]; ];
const handleViewActivities = (project) => { // const handleViewActivities = (project) => {
dispatch(setProjectId(project)); // dispatch(setProjectId(project));
navigate(`/activities/records?project=${project}`); // navigate(`/activities/records?project=${project}`);
}; // };
const handleMoveDetails = (project) => {
dispatch(setProjectId(project));
navigate("/projects/details");
};
return ( return (
<div className="card page-min-h py-4 px-6 shadow-sm"> <div className="card page-min-h py-4 px-6 shadow-sm">
<table className="table table-hover align-middle m-0"> <table className="table table-hover align-middle m-0">
@ -158,11 +161,7 @@ const ProjectListView = ({
: project[col.key] || "N/A"} : project[col.key] || "N/A"}
</td> </td>
))} ))}
<td <td className={`mx-2 ${"d-sm-table-cell"}`}>
className={`mx-2 ${
canManageProject ? "d-sm-table-cell" : "d-none"
}`}
>
<div className="dropdown z-2"> <div className="dropdown z-2">
<button <button
type="button" type="button"
@ -180,7 +179,7 @@ const ProjectListView = ({
></i> ></i>
</button> </button>
<ul className="dropdown-menu dropdown-menu-end"> <ul className="dropdown-menu dropdown-menu-end">
<li> <li onClick={() => handleMoveDetails(project.id)}>
<a <a
aria-label="click to View details" aria-label="click to View details"
className="dropdown-item cursor-pointer" className="dropdown-item cursor-pointer"
@ -204,12 +203,12 @@ const ProjectListView = ({
<span className="align-left">Modify</span> <span className="align-left">Modify</span>
</a> </a>
</li> </li>
<li onClick={() => handleViewActivities(project.id)}> {/* <li onClick={() => handleViewActivities(project.id)}>
<a className="dropdown-item cursor-pointer"> <a className="dropdown-item cursor-pointer">
<i className="bx bx-task me-2"></i> <i className="bx bx-task me-2"></i>
<span className="align-left">Activities</span> <span className="align-left">Activities</span>
</a> </a>
</li> </li> */}
</ul> </ul>
</div> </div>
</td> </td>

View File

@ -120,7 +120,7 @@ export const useUploadDocument = (onSuccessCallBack) => {
DocumentRepository.uploadDocument(DocumentPayload), DocumentRepository.uploadDocument(DocumentPayload),
onSuccess: (data, variables) => { onSuccess: (data, variables) => {
queryClient.invalidateQueries({ queryKey: ["DocumentList"] }); queryClient.invalidateQueries({ queryKey: ["DocumentList"] });
queryClient.invalidateQueries({ queryKey: ["Document"] });
if (onSuccessCallBack) onSuccessCallBack(); if (onSuccessCallBack) onSuccessCallBack();
}, },
onError: (error) => { onError: (error) => {
@ -141,7 +141,7 @@ export const useUpdateDocument = (onSuccessCallBack) => {
onSuccess: (data, variables) => { onSuccess: (data, variables) => {
const { documentId } = variables; const { documentId } = variables;
queryClient.invalidateQueries({ queryKey: ["DocumentList"] }); queryClient.invalidateQueries({ queryKey: ["DocumentList"] });
queryClient.invalidateQueries({ queryKey: ["Document", documentId] }); queryClient.invalidateQueries({ queryKey: ["Document"] });
if (onSuccessCallBack) onSuccessCallBack(); if (onSuccessCallBack) onSuccessCallBack();
}, },
onError: (error) => { onError: (error) => {
@ -187,6 +187,7 @@ export const useActiveInActiveDocument = ()=>{
onSuccess: (data, variables) => { onSuccess: (data, variables) => {
const {isActive} = variables; const {isActive} = variables;
queryClient.invalidateQueries({ queryKey: ["DocumentList"] }); queryClient.invalidateQueries({ queryKey: ["DocumentList"] });
queryClient.invalidateQueries({ queryKey: ["Document"] });
showToast(`Document ${isActive ? "restored":"Deleted"} successfully`,"success") showToast(`Document ${isActive ? "restored":"Deleted"} successfully`,"success")
}, },
onError: (error) => { onError: (error) => {

View File

@ -44,7 +44,7 @@ export default function DirectoryPage({ IsPage = true, projectId = null }) {
const [searchNote, setSearchNote] = useState(""); const [searchNote, setSearchNote] = useState("");
const [activeTab, setActiveTab] = useState("notes"); const [activeTab, setActiveTab] = useState("notes");
const { setActions } = useFab(); const { setActions } = useFab();
const [gridView, setGridView] = useState(false); const [gridView, setGridView] = useState(true);
const [isOpenBucket, setOpenBucket] = useState(false); const [isOpenBucket, setOpenBucket] = useState(false);
const [isManageContact, setManageContact] = useState({ const [isManageContact, setManageContact] = useState({
isOpen: false, isOpen: false,
@ -185,14 +185,7 @@ export default function DirectoryPage({ IsPage = true, projectId = null }) {
value={searchContact} value={searchContact}
onChange={(e) => setsearchContact(e.target.value)} onChange={(e) => setsearchContact(e.target.value)}
/> />
<button
className={`btn btn-sm p-1 ${
!gridView ? "btn-primary" : "btn-outline-primary"
}`}
onClick={() => setGridView(false)}
>
<i className="bx bx-list-ul"></i>
</button>
<button <button
className={`btn btn-sm p-1 ${ className={`btn btn-sm p-1 ${
@ -202,6 +195,15 @@ export default function DirectoryPage({ IsPage = true, projectId = null }) {
> >
<i className="bx bx-grid-alt"></i> <i className="bx bx-grid-alt"></i>
</button> </button>
<button
className={`btn btn-sm p-1 ${
!gridView ? "btn-primary" : "btn-outline-primary"
}`}
onClick={() => setGridView(false)}
>
<i className="bx bx-list-ul"></i>
</button>
</div> </div>
<div className="form-check form-switch d-flex align-items-center"> <div className="form-check form-switch d-flex align-items-center">

View File

@ -60,12 +60,12 @@ const NoteFilterPanel = ({ onApply, clearFilter }) => {
<div className="d-flex justify-content-end py-3 gap-2"> <div className="d-flex justify-content-end py-3 gap-2">
<button <button
type="button" type="button"
className="btn btn-label-secondary btn-xs" className="btn btn-label-secondary btn-sm"
onClick={handleClose} onClick={handleClose}
> >
Clear Clear
</button> </button>
<button type="submit" className="btn btn-primary btn-xs"> <button type="submit" className="btn btn-primary btn-sm">
Apply Apply
</button> </button>
</div> </div>

View File

@ -51,11 +51,7 @@ const EmployeeList = () => {
const Manage_Employee = useHasUserPermission(MANAGE_EMPLOYEES); const Manage_Employee = useHasUserPermission(MANAGE_EMPLOYEES);
const { employees, loading, setLoading, error, recallEmployeeData } = const { employees, loading, setLoading, error, recallEmployeeData } =
useEmployeesAllOrByProjectId( useEmployeesAllOrByProjectId(showAllEmployees, null, showInactive);
showAllEmployees,
null,
showInactive
);
const [employeeList, setEmployeeList] = useState([]); const [employeeList, setEmployeeList] = useState([]);
const [modelConfig, setModelConfig] = useState(); const [modelConfig, setModelConfig] = useState();
@ -206,17 +202,11 @@ const EmployeeList = () => {
} }
}, [loading, employees, showAllEmployees]); }, [loading, employees, showAllEmployees]);
const handler = useCallback( const handler = useCallback(
(msg) => { (msg) => {
if (employees.some((item) => item.id == msg.employeeId)) { if (employees.some((item) => item.id == msg.employeeId)) {
setEmployeeList([]); setEmployeeList([]);
recallEmployeeData( recallEmployeeData(showInactive, null, showAllEmployees);
showInactive,
null,
showAllEmployees
);
} }
}, },
[employees, showInactive, showAllEmployees] [employees, showInactive, showAllEmployees]
@ -289,12 +279,10 @@ const EmployeeList = () => {
{ViewTeamMember ? ( {ViewTeamMember ? (
// <div className="row"> // <div className="row">
<div className="card page-min-h p-1"> <div className="card page-min-h ">
<div className="card-datatable table-responsive pt-5 mx-5 py-10">
<div <div
id="DataTables_Table_0_wrapper" id="DataTables_Table_0_wrapper"
className="dataTables_wrapper dt-bootstrap5 no-footer" className="dataTables_wrapper dt-bootstrap5 no-footer p-1 pt-5 mx-5 py-10"
style={{ width: "100%" }}
> >
<div className="d-flex flex-wrap align-items-center justify-content-between gap-3 mb-3"> <div className="d-flex flex-wrap align-items-center justify-content-between gap-3 mb-3">
{/* Switches: All Employees + Inactive */} {/* Switches: All Employees + Inactive */}
@ -521,27 +509,23 @@ const EmployeeList = () => {
{/* Conditional messages for no data or no search results */} {/* Conditional messages for no data or no search results */}
{!loading && {!loading &&
displayData?.length === 0 && displayData?.length === 0 &&
searchText && searchText ? (
!showAllEmployees ? (
<tr> <tr>
<td colSpan={8}> <td colSpan={8} className="border-0">
<div className="py-12">
<small className="muted"> <small className="muted">
'{searchText}' employee not found '{searchText}' employee not found
</small>{" "} </small>{" "}
</div>
</td> </td>
</tr> </tr>
) : null} ) : null}
{!loading && {!loading &&
displayData?.length === 0 && displayData?.length === 0 &&
(!searchText || showAllEmployees) ? ( (!searchText ) ? (
<tr> <tr>
<td <td colSpan={8} className="border-0">
colSpan={8} <div className="py-12">{showInactive ? "No In-active Employeee Found" : "No Employeee Found" }</div>
className="border-0"
>
<div className="py-1">
No Employeee Found
</div>
</td> </td>
</tr> </tr>
) : null} ) : null}
@ -559,9 +543,7 @@ const EmployeeList = () => {
></Avatar> ></Avatar>
<div className="d-flex flex-column"> <div className="d-flex flex-column">
<a <a
onClick={() => onClick={() => navigate(`/employee/${item.id}`)}
navigate(`/employee/${item.id}`)
}
className="text-heading text-truncate cursor-pointer" className="text-heading text-truncate cursor-pointer"
> >
<span className="fw-normal"> <span className="fw-normal">
@ -579,9 +561,7 @@ const EmployeeList = () => {
{item.email} {item.email}
</span> </span>
) : ( ) : (
<span className="text-truncate text-italic"> <span className="text-truncate text-italic">-</span>
-
</span>
)} )}
</td> </td>
<td className="text-start d-none d-sm-table-cell"> <td className="text-start d-none d-sm-table-cell">
@ -646,8 +626,7 @@ const EmployeeList = () => {
handleEmployeeModel(item.id) handleEmployeeModel(item.id)
} }
> >
<i className="bx bx-edit bx-sm"></i>{" "} <i className="bx bx-edit bx-sm"></i> Edit
Edit
</button> </button>
{/* Suspend only when active */} {/* Suspend only when active */}
@ -670,8 +649,8 @@ const EmployeeList = () => {
setEmpForManageRole(item.id) setEmpForManageRole(item.id)
} }
> >
<i className="bx bx-cog bx-sm"></i>{" "} <i className="bx bx-cog bx-sm"></i> Manage
Manage Role Role
</button> </button>
</> </>
)} )}
@ -704,7 +683,6 @@ const EmployeeList = () => {
)} )}
</div> </div>
</div> </div>
</div>
) : ( ) : (
<div className="card"> <div className="card">
<div className="text-center"> <div className="text-center">

View File

@ -161,8 +161,8 @@ const MasterPage = () => {
data={[{ label: "Home", link: "/dashboard" }, { label: "Masters" }]} data={[{ label: "Home", link: "/dashboard" }, { label: "Masters" }]}
/> />
<div className="row">
<div className="card"> <div className="card page-min-h">
<div <div
className="card-datatable table-responsive py-10 mx-5 " className="card-datatable table-responsive py-10 mx-5 "
style={{ overflow: "hidden" }} style={{ overflow: "hidden" }}
@ -223,7 +223,6 @@ const MasterPage = () => {
</div> </div>
</div> </div>
</div> </div>
</div>
</MasterContext.Provider> </MasterContext.Provider>
); );
}; };

View File

@ -109,11 +109,11 @@ const MasterTable = ({ data, columns, loading, handleModalData }) => {
{currentItems.length > 0 ? ( {currentItems.length > 0 ? (
currentItems.map((item, index) => ( currentItems.map((item, index) => (
<tr key={index}> <tr key={index}>
<td style={{ width: "20px" }}> <td style={{ width: "20px", }} className="py-5">
<i className="bx bx-right-arrow-alt"></i> <div className="py-2 px-3"><i className="bx bx-right-arrow-alt"></i></div>
</td> </td>
{updatedColumns.map((col) => ( {updatedColumns.map((col) => (
<td className="text-start mx-2" key={col.key}> <td className="text-start mx-2 p-3" key={col.key} style={{ padding: "12px 16px" }} >
{col.key === "description" ? ( {col.key === "description" ? (
item[col.key] !== undefined && item[col.key] !== undefined &&
item[col.key] !== null ? ( item[col.key] !== null ? (

View File

@ -32,100 +32,104 @@ export function startSignalR(loggedUser) {
.toISOString() .toISOString()
.split("T")[0]; .split("T")[0];
connection.on("NotificationEventHandler", (data) => { connection.on("NotificationEventHandler", (data) => {
if (data.loggedInUserId != loggedUser?.employeeInfo.id) { const { loggedInUserId, keyword, response, employeeList, numberOfImages } = data;
// console.log("Notification received:", data); const loggedInId = loggedUser?.employeeInfo?.id;
// if action taken on attendance module
if (data.keyword == "Attendance") {
const checkIn = data.response.checkInTime.substring(0, 10);
if (today === checkIn) {
eventBus.emit("attendance", data);
}
var onlyDate = Number(checkIn.substring(8, 10));
var afterTwoDay = if (loggedInUserId === loggedInId) return;
// ---- Handlers for invalidate or remove ----
const queryInvalidators = {
Expanse: () => {
queryClient.invalidateQueries({ queryKey: ["Expenses"] }),
queryClient.invalidateQueries({ queryKey: ["Expense"] })
},
Create_Project: () => queryClient.invalidateQueries(["projectslist"]),
Update_Project: () => queryClient.invalidateQueries(["projectslist"]),
Infra: () => queryClient.removeQueries({ queryKey: ["ProjectInfra"] }),
Task_Report: () => queryClient.invalidateQueries({ queryKey: ["Infra"] }),
WorkItem: () => queryClient.invalidateQueries({ queryKey: ["WorkItems"] }),
Directory_Notes:()=>{
queryClient.invalidateQueries({queryKey:["directoryNotes"]})
queryClient.invalidateQueries({queryKey:["Notes"]})
},
Directory_Buckets:()=>{
queryClient.invalidateQueries({queryKey:["bucketList"]})
},
Directory:()=>{
queryClient.invalidateQueries({queryKey:["contacts"]})
queryClient.invalidateQueries({queryKey:["Contact"]})
queryClient.invalidateQueries({queryKey:["ContactProfile"]})
}
};
// ---- Keyword based event emitters ----
const emitters = {
employee: () => eventBus.emit("employee", data),
project: () => eventBus.emit("project", data),
infra: () => eventBus.emit("infra", data),
assign_project_all: () => eventBus.emit("assign_project_all", data),
image_gallery: () => eventBus.emit("image_gallery", data),
};
// ---- Handle Attendance ----
if (keyword === "Attendance") {
const checkIn = response.checkInTime.substring(0, 10);
if (today === checkIn) eventBus.emit("attendance", data);
const onlyDate = Number(checkIn.substring(8, 10));
const afterTwoDay =
checkIn.substring(0, 8) + (onlyDate + 2).toString().padStart(2, "0"); checkIn.substring(0, 8) + (onlyDate + 2).toString().padStart(2, "0");
if ( if (
afterTwoDay <= today && afterTwoDay <= today &&
(data.response.activity == 4 || data.response.activity == 5) (response.activity === 4 || response.activity === 5)
) { ) {
eventBus.emit("regularization", data); eventBus.emit("regularization", data);
} }
eventBus.emit("attendance_log", data); eventBus.emit("attendance_log", data);
} }
if(data.keyword == "Expanse"){
queryClient.invalidateQueries({queryKey:["Expenses"]}) // ---- Invalidate/Remove cache by keywords ----
} if (queryInvalidators[keyword]) {
// if create or update project queryInvalidators[keyword]();
if (
data.keyword == "Create_Project" ||
data.keyword == "Update_Project"
) {
// clearCacheKey("projectslist");
queryClient.invalidateQueries(['projectslist']);
eventBus.emit("project", data);
} }
// if assign or deassign employee to any project // ---- Project creation/update ----
if (data.keyword == "Assign_Project") { if (keyword === "Create_Project" || keyword === "Update_Project") {
if ( emitters.project();
data.employeeList.some((item) => item === loggedUser?.employeeInfo.id) }
) {
// ---- Assign/deassign project ----
if (keyword === "Assign_Project") {
if (employeeList?.includes(loggedInId)) {
try { try {
cacheData("hasReceived", false); cacheData("hasReceived", false);
eventBus.emit("assign_project_one", data); eventBus.emit("assign_project_one", data);
} catch (e) { } catch {}
// console.error("Error in cacheData:", e);
} }
} emitters.assign_project_all();
eventBus.emit("assign_project_all", data);
}
// if created or updated infra
if (data.keyword == "Infra") {
queryClient.removeQueries({queryKey:["ProjectInfra"]})
// eventBus.emit("infra", data);
}
if (data.keyword == "Task_Report") {
queryClient.removeQueries({queryKey:["Infra"]})
// eventBus.emit("infra", data);
} }
if ( data.keyword == "WorkItem" ) // ---- Employee update ----
{ if (keyword === "Employee") {
queryClient.removeQueries({queryKey:["WorkItems"]})
}
// if created or updated Employee
if (data.keyword == "Employee") {
// clearCacheKey("employeeListByProject");
// clearCacheKey("allEmployeeList");
// clearCacheKey("allInactiveEmployeeList");
// clearCacheKey("employeeProfile");
clearCacheKey("Attendance"); clearCacheKey("Attendance");
clearCacheKey("regularizedList") clearCacheKey("regularizedList");
clearCacheKey("AttendanceLogs") clearCacheKey("AttendanceLogs");
// ---we can do also---- queryClient.invalidateQueries(["allEmployee", true]);
// queryClient.removeQueries(['allEmployee', true]); queryClient.invalidateQueries(["allEmployee", false]);
// but best practies is refetch queryClient.invalidateQueries(["employeeProfile", response?.employeeId]);
queryClient.invalidateQueries(['allEmployee', true]); queryClient.invalidateQueries(["employeeListByProject"]);
queryClient.invalidateQueries(['allEmployee', false]);
queryClient.invalidateQueries(['employeeProfile', data.response?.employeeId]); emitters.employee();
queryClient.invalidateQueries(['employeeListByProject']); // optional if scope
eventBus.emit("employee", data);
} }
if (data.keyword == "Task_Report") { // ---- Image related events ----
if(data.numberOfImages > 0){ if (["Task_Report", "Task_Comment"].includes(keyword) && numberOfImages > 0) {
eventBus.emit("image_gallery", data); emitters.image_gallery();
} }
} });
if (data.keyword == "Task_Comment") {
if(data.numberOfImages > 0){
eventBus.emit("image_gallery", data);
}
}
}
});
connection connection
.start(); .start();