Implemented signalR for create and update project

This commit is contained in:
ashutosh.nehete 2025-06-12 19:39:56 +05:30
parent f8ee3d3a86
commit 164f3cc02f
8 changed files with 160 additions and 72 deletions

View File

@ -1,9 +1,13 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import moment from "moment";
import { getProjectStatusName } from "../../utils/projectStatus";
const AboutProject = ({ data }) => {
const [CurrentProject, setCurrentProject] = useState(data);
useEffect(() => {
setCurrentProject(data);
}, [data]);
return (
<>
{data && (

View File

@ -12,10 +12,15 @@ const ProjectBanner = ({ project_data }) => {
const [showModal, setShowModal] = useState(false);
const manageProject = useHasUserPermission(MANAGE_PROJECT);
const [CurrentProject, setCurrentProject] = useState(project_data);
if (project_data == null) {
return <span>incomplete project information</span>;
}
useEffect(() => {
setCurrentProject(project_data);
}, [project_data]);
const handleShow = () => setShowModal(true);
const handleClose = () => setShowModal(false);

View File

@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import moment from "moment";
import { getDateDifferenceInDays } from "../../utils/dateUtils";
import { useNavigate } from "react-router-dom";
@ -22,6 +22,9 @@ const ProjectCard = ({ projectData, recall }) => {
const ManageProject = useHasUserPermission(MANAGE_PROJECT);
const [modifyProjectLoading, setMdifyProjectLoading] = useState(false);
useEffect(()=>{
setProjectInfo(projectData);
},[projectData])
const handleShow = async () => {
try {
setMdifyProjectLoading(true);

View File

@ -58,7 +58,7 @@ const AttendancePage = () => {
setAttendances(updatedAttendance);
}
},
[selectedProject, attrecall]
[selectedProject,attendances]
);
const getRole = (roleId) => {

View File

@ -1,5 +1,5 @@
import { useParams } from "react-router-dom";
import React, { useState, useEffect } from "react";
import React, { useState, useEffect, useCallback } from "react";
import ActivityTimeline from "../../components/Project/ActivityTimeline";
import ProjectOverview from "../../components/Project/ProjectOverview";
@ -11,7 +11,7 @@ import ProjectInfra from "../../components/Project/ProjectInfra";
import Loader from "../../components/common/Loader";
import WorkPlan from "../../components/Project/WorkPlan";
import Breadcrumb from "../../components/common/Breadcrumb";
import { cacheData, getCachedData } from "../../slices/apiDataManager";
import { cacheData, clearCacheKey, getCachedData } from "../../slices/apiDataManager";
import ProjectRepository from "../../repositories/ProjectRepository";
import { ActivityeRepository } from "../../repositories/MastersRepository";
import "./ProjectDetails.css";
@ -23,6 +23,7 @@ import { useDispatch } from "react-redux";
import { setProjectId } from "../../slices/localVariablesSlice";
import { ComingSoonPage } from "../Misc/ComingSoonPage";
import Directory from "../Directory/Directory";
import eventBus from "../../services/eventBus";
const ProjectDetails = () => {
let { projectId } = useParams();
@ -121,7 +122,7 @@ const ProjectDetails = () => {
case "directory": {
return (
<div className="row">
<Directory IsPage={ false} prefernceContacts={projectDetails.id} />
<Directory IsPage={false} prefernceContacts={projectDetails.id} />
</div>
);
}
@ -137,6 +138,31 @@ const ProjectDetails = () => {
setProjectDetails(projects_Details);
}, [projects_Details, projectId]);
const handler = useCallback(
(msg) => {
if (msg.keyword === "Update_Project" && project.id === msg.response.id) {
clearCacheKey("projectInfo")
ProjectRepository.getProjectByprojectId(projectId)
.then((response) => {
setProjectDetails(response.data);
setProject(response.data);
cacheData("projectInfo", { projectId, data: response.data });
setLoading(false);
})
.catch((error) => {
console.error(error);
setError("Failed to fetch data.");
setLoading(false);
});
}
},
[project,handleDataChange]
);
useEffect(() => {
eventBus.on("project", handler);
return () => eventBus.off("project", handler);
}, [handler]);
return (
<>
{}

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react";
import React, { useState, useEffect, useCallback } from "react";
import ProjectCard from "../../components/Project/ProjectCard";
import ManageProjectInfo from "../../components/Project/ManageProjectInfo";
import Breadcrumb from "../../components/common/Breadcrumb";
@ -11,6 +11,8 @@ import { useHasUserPermission } from "../../hooks/useHasUserPermission";
import { useProfile } from "../../hooks/useProfile";
import { ITEMS_PER_PAGE, MANAGE_PROJECT } from "../../utils/constants";
import ProjectListView from "./ProjectListView";
import eventBus from "../../services/eventBus";
import { clearApiCacheKey } from "../../slices/apiCacheSlice";
const ProjectList = () => {
const { profile: loginUser } = useProfile();
@ -37,7 +39,7 @@ const ProjectList = () => {
const handleShow = () => setShowModal(true);
const handleClose = () => setShowModal(false);
const sortingProject = (projects) =>{
const sortingProject = (projects) => {
if (!loading && Array.isArray(projects)) {
const grouped = {};
projects.forEach((project) => {
@ -56,10 +58,10 @@ const ProjectList = () => {
setProjectList(sortedGrouped);
}
}
};
useEffect(() => {
sortingProject(projects)
sortingProject(projects);
}, [projects, loginUser?.projects, loading]);
useEffect(() => {
@ -70,16 +72,16 @@ const ProjectList = () => {
}
}, [loginUser, HasManageProjectPermission]);
const handleSubmitForm = (newProject,setloading,reset) => {
const handleSubmitForm = (newProject, setloading, reset) => {
ProjectRepository.manageProject(newProject)
.then((response) => {
const cachedProjects = getCachedData("projectslist") || [];
const updatedProjects = [...cachedProjects, response.data];
cacheData("projectslist", updatedProjects);
setProjectList( ( prev ) => [ ...prev, response.data ] );
setloading( false )
reset()
sortingProject(getCachedData("projectslist"))
setProjectList((prev) => [...prev, response.data]);
setloading(false);
reset();
sortingProject(getCachedData("projectslist"));
showToast("Project Created successfully.", "success");
setShowModal(false);
})
@ -123,7 +125,7 @@ const ProjectList = () => {
indexOfLastItem
);
const totalPages = Math.ceil(filteredProjects.length / itemsPerPage);
console.log("filtter", currentItems);
useEffect(() => {
const tooltipTriggerList = Array.from(
document.querySelectorAll('[data-bs-toggle="tooltip"]')
@ -131,6 +133,31 @@ const ProjectList = () => {
tooltipTriggerList.forEach((el) => new bootstrap.Tooltip(el));
}, []);
const handler = useCallback(
async (msg) => {
if (HasManageProject && msg.keyword === "Create_Project") {
const updatedProjects = [...projectList, msg.response];
cacheData("projectslist", updatedProjects);
setProjectList(updatedProjects);
sortingProject(updatedProjects);
}
if (
msg.keyword === "Update_Project" &&
projectList.some((item) => item.id === msg.response.id)
) {
await refetch();
sortingProject(projects);
}
},
[HasManageProject, projects, sortingProject]
);
useEffect(() => {
eventBus.on("project", handler);
return () => eventBus.off("project", handler);
}, [handler]);
return (
<>
<div
@ -200,49 +227,48 @@ const ProjectList = () => {
<i className="bx bx-list-ul bx-sm"></i>
</button>
</div>
<div className="dropdown ms-3">
<a
className="dropdown-toggle hide-arrow cursor-pointer"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<i className="bx bx-filter bx-lg"></i>
</a>
<ul className="dropdown-menu p-2 text-capitalize">
{[
{
id: "b74da4c2-d07e-46f2-9919-e75e49b12731",
label: "Active",
},
{
id: "603e994b-a27f-4e5d-a251-f3d69b0498ba",
label: "On Hold",
},
{
id: "ef1c356e-0fe0-42df-a5d3-8daee355492d",
label: "Inactive",
},
{
id: "33deaef9-9af1-4f2a-b443-681ea0d04f81",
label: "Completed",
},
].map(({ id, label }) => (
<li key={id}>
<div className="form-check">
<input
className="form-check-input "
type="checkbox"
checked={selectedStatuses.includes(id)}
onChange={() => handleStatusChange(id)}
/>
<label className="form-check-label">{label}</label>
</div>
</li>
))}
</ul>
</div>
<div className="dropdown ms-3">
<a
className="dropdown-toggle hide-arrow cursor-pointer"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<i className="bx bx-filter bx-lg"></i>
</a>
<ul className="dropdown-menu p-2 text-capitalize">
{[
{
id: "b74da4c2-d07e-46f2-9919-e75e49b12731",
label: "Active",
},
{
id: "603e994b-a27f-4e5d-a251-f3d69b0498ba",
label: "On Hold",
},
{
id: "ef1c356e-0fe0-42df-a5d3-8daee355492d",
label: "Inactive",
},
{
id: "33deaef9-9af1-4f2a-b443-681ea0d04f81",
label: "Completed",
},
].map(({ id, label }) => (
<li key={id}>
<div className="form-check">
<input
className="form-check-input "
type="checkbox"
checked={selectedStatuses.includes(id)}
onChange={() => handleStatusChange(id)}
/>
<label className="form-check-label">{label}</label>
</div>
</li>
))}
</ul>
</div>
</div>
<div>
@ -341,7 +367,11 @@ const ProjectList = () => {
</tr>
) : (
currentItems.map((project) => (
<ProjectListView key={project.id} projectData={project} recall={sortingProject} />
<ProjectListView
key={project.id}
projectData={project}
recall={sortingProject}
/>
))
)}
</tbody>
@ -349,7 +379,11 @@ const ProjectList = () => {
</div>
) : (
currentItems.map((project) => (
<ProjectCard key={project.id} projectData={project} recall={sortingProject} />
<ProjectCard
key={project.id}
projectData={project}
recall={sortingProject}
/>
))
)}
</div>

View File

@ -22,6 +22,10 @@ const ProjectListView = ({ projectData, recall }) => {
const navigate = useNavigate();
const ManageProject = useHasUserPermission(MANAGE_PROJECT);
useEffect(()=>{
setProjectInfo(projectData);
},[projectData])
const handleShow = async () => {
try {
const response = await ProjectRepository.getProjectByprojectId(

View File

@ -3,6 +3,7 @@ import { clearCacheKey, getCachedData } from "../slices/apiDataManager";
import showToast from "./toastService";
import eventBus from "./eventBus";
import { useSelector } from "react-redux";
import { clearApiCacheKey } from "../slices/apiCacheSlice";
const base_Url = process.env.VITE_BASE_URL;
// const base_Url = "https://devapi.marcoaiot.com";
let connection = null;
@ -25,19 +26,30 @@ export function startSignalR(loggedUser) {
)
.toISOString()
.split("T")[0];
connection.on("Attendance", (data) => {
const checkIn = data.response.checkInTime.substring(0, 10);
if (data.loginUserId != loggedUser?.employeeInfo.id) {
if (today === checkIn) {
eventBus.emit("attendance", data);
}
var onlyDate = Number(checkIn.substring(8, 10));
connection.on("NotificationEventHandler", (data) => {
// console.log("Notification received:", data);
if (data.keyword == "Attendance") {
const checkIn = data.response.checkInTime.substring(0, 10);
if (data.loginUserId != loggedUser?.employeeInfo.id) {
if (today === checkIn) {
eventBus.emit("attendance", data);
}
var onlyDate = Number(checkIn.substring(8, 10));
var afterTwoDay = checkIn.substring(0, 8) + (onlyDate + 2).toString().padStart(2, "0");;
if(afterTwoDay <= today && (data.response.activity == 4 || data.response.activity == 5)){
eventBus.emit("regularization", data);
var afterTwoDay =
checkIn.substring(0, 8) + (onlyDate + 2).toString().padStart(2, "0");
if (
afterTwoDay <= today &&
(data.response.activity == 4 || data.response.activity == 5)
) {
eventBus.emit("regularization", data);
}
eventBus.emit("attendance_log", data);
}
eventBus.emit("attendance_log", data);
}
if (data.keyword == "Create_Project" || data.keyword == "Update_Project") {
clearCacheKey("projectslist");
eventBus.emit("project", data);
}
});