added serviceproject list

This commit is contained in:
pramod.mahajan 2025-11-17 10:57:48 +05:30
parent 3d1d8264ad
commit 8eb34addcd
8 changed files with 172 additions and 66 deletions

View File

@ -9,14 +9,14 @@ import { useParams } from "react-router-dom";
import ProjectPage from "../../pages/project/ProjectPage"; import ProjectPage from "../../pages/project/ProjectPage";
import { useServiceProjectJobContext } from "./Jobs"; import { useServiceProjectJobContext } from "./Jobs";
const JobList = ({ filterByProject }) => { const JobList = () => {
const { setSelectedJob, setManageJob } = useServiceProjectJobContext(); const { setSelectedJob, setManageJob } = useServiceProjectJobContext();
const { id } = useParams(); const { projectId } = useParams();
const { data, isLoading, isError, error } = useServiceProjectJobs( const { data, isLoading, isError, error } = useServiceProjectJobs(
ITEMS_PER_PAGE, ITEMS_PER_PAGE,
1, 1,
true, true,
filterByProject ?? id projectId
); );
const jobGrid = [ const jobGrid = [

View File

@ -2,14 +2,12 @@ import React from "react";
import Avatar from "../common/Avatar"; import Avatar from "../common/Avatar";
const JobStatusLog = ({ data }) => { const JobStatusLog = ({ data }) => {
console.log(data) console.log(data);
return ( return (
<div className="card shadow-none p-0"> <div className="card shadow-none p-0">
<div className="card-body p-0"> <div className="card-body p-0">
<div className="list-group"> <div className="list-group">
{data?.map((item) => ( {data?.map((item) => (
<div <div
key={item.id} key={item.id}
className="list-group-item border-0 border-bottom p-1" className="list-group-item border-0 border-bottom p-1"
@ -17,13 +15,15 @@ const JobStatusLog = ({ data }) => {
<div className="d-flex justify-content-between"> <div className="d-flex justify-content-between">
<div> <div>
<span className="fw-semibold"> <span className="fw-semibold">
{item.nextStatus?.displayName ?? item.status?.displayName ?? "Status"} {item.nextStatus?.displayName ??
item.status?.displayName ??
"Status"}
</span> </span>
</div> </div>
<span className="badge bg-primary"> {/* <span className="badge bg-primary">
Level {item.nextStatus?.level ?? item.status?.level} Level {item.nextStatus?.level ?? item.status?.level}
</span> </span> */}
</div> </div>
<div className="d-flex align-items-start mt-2 mx-0 px-0"> <div className="d-flex align-items-start mt-2 mx-0 px-0">
<Avatar <Avatar
@ -44,13 +44,11 @@ const JobStatusLog = ({ data }) => {
</div> </div>
<div className="text-wrap"> <div className="text-wrap">
<p className="mb-1 mt-2 text-muted">{item.comment}</p> <p className="mb-1 mt-2 text-muted">{item.comment}</p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
))} ))}
</div> </div>
</div> </div>
</div> </div>

View File

@ -16,7 +16,7 @@ const ManageJobTicket = ({ Job }) => {
const tabsData = [ const tabsData = [
{ {
id: "comment", id: "comment",
title: "Coments", title: "Comments",
icon:"bx bx-comment me-2", icon:"bx bx-comment me-2",
active: true, active: true,
content: <JobComments data={data} />, content: <JobComments data={data} />,
@ -58,7 +58,7 @@ const ManageJobTicket = ({ Job }) => {
</span>{" "} </span>{" "}
<i className="bx bx-right-arrow-alt"></i>{" "} <i className="bx bx-right-arrow-alt"></i>{" "}
<span className="fw-medium"> <span className="fw-medium">
<i className="bx bx-calendar"></i> Due To : {formatUTCToLocalTime(data?.startDate)} <i className="bx bx-calendar"></i> Due on : {formatUTCToLocalTime(data?.startDate)}
</span> </span>
</div> </div>
<div className="d-block mt-2"> <div className="d-block mt-2">
@ -71,9 +71,9 @@ const ManageJobTicket = ({ Job }) => {
firstName={data?.createdBy?.firstName} firstName={data?.createdBy?.firstName}
lastName={data?.createdBy?.lastName} lastName={data?.createdBy?.lastName}
/>{" "} />{" "}
<div className="d-flex flex-column"> <div className="d-flex flex-row align-items-center">
<p className="m-0">{`${data?.createdBy?.firstName} ${data?.createdBy?.lastName}`}</p> <p className="m-0">{`${data?.createdBy?.firstName} ${data?.createdBy?.lastName}`}</p>
<small className="text-secondary">{data?.createdBy?.jobRoleName}</small> <small className="text-secondary ms-1">({data?.createdBy?.jobRoleName})</small>
</div> </div>
</div> </div>
<div className="d-flex align-items-center"> <div className="d-flex align-items-center">
@ -84,9 +84,9 @@ const ManageJobTicket = ({ Job }) => {
{data?.assignees?.map((emp)=>( {data?.assignees?.map((emp)=>(
<div className="d-flex flex-row "> <div className="d-flex flex-row ">
<Avatar size="xs" firstName={emp.firstName} lastName={emp.lastName}/> <Avatar size="xs" firstName={emp.firstName} lastName={emp.lastName}/>
<div className="d-flex flex-column"> <div className="d-flex flex-row align-items-center">
<p className="m-0">{`${emp.firstName} ${emp.lastName}`}</p> <p className="m-0">{`${emp.firstName} ${emp.lastName}`}</p>
<small className="text-secondary">{emp.jobRoleName}</small> <small className="text-secondary ms-1">( {emp.jobRoleName} )</small>
</div> </div>
</div> </div>
))} ))}

View File

@ -1,6 +1,7 @@
import React from 'react' import React from 'react'
import { useModal } from '../../../hooks/useAuth' import { useModal } from '../../../hooks/useAuth'
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import ServiceProjectTeamList from './ServiceProjectTeamList';
const ProjectTeam = () => { const ProjectTeam = () => {
@ -8,13 +9,13 @@ const {onOpen} = useModal("ServiceTeamAllocation");
const {projectId}= useParams(); const {projectId}= useParams();
return ( return (
<div className='card page-min-h mt-2'> <div className='card page-min-h mt-2 px-4'>
<div className='row text-end'> <div className='row text-end'>
<div className='col-12'> <div className='col-12'>
<div className='p-2'><button onClick={()=>onOpen({projectId:projectId})} className='btn btn-sm btn-primary'><i className='bx bx-plus-circle me-2'></i>Assign Employee</button></div> <div className='p-2'><button onClick={()=>onOpen({projectId:projectId})} className='btn btn-sm btn-primary'>Manage Employee</button></div>
</div> </div>
</div> </div>
{/* <ServiceProjectTeamList/> */} <ServiceProjectTeamList/>
</div> </div>
) )
} }

View File

@ -71,15 +71,12 @@ const ServiceProjectTeamAllocation = () => {
}, },
]; ];
AllocationTeam({payload:payload,isActive:false}); AllocationTeam({ payload: payload, isActive: false });
}; };
useEffect(() => { useEffect(() => {
if(selectedEmployees?.length > 0 && !selectedTeam){ if (selectedEmployees?.length > 0 && !selectedTeam) {
handleRemove(selectedEmployees[0]?.id) handleRemove(selectedEmployees[0]?.id);
showToast( showToast(`Please select a first role`, "warning");
`Please select a first role`,
"warning"
);
} }
if (Team?.length > 0 && selectedEmployees?.length > 0) { if (Team?.length > 0 && selectedEmployees?.length > 0) {
setNonDuplicateEmployee((prev) => { setNonDuplicateEmployee((prev) => {
@ -113,7 +110,7 @@ const ServiceProjectTeamAllocation = () => {
className="btn btn-sm btn-primary" className="btn btn-sm btn-primary"
onClick={() => setIsMenageEmployee(!isManageEmployee)} onClick={() => setIsMenageEmployee(!isManageEmployee)}
> >
Manage Employee <i className="bx bx-plus-circle me-2"></i>Add Employee
</button> </button>
</div> </div>
@ -137,6 +134,7 @@ const ServiceProjectTeamAllocation = () => {
<div className="col-12 col-md-6 mb-3"> <div className="col-12 col-md-6 mb-3">
<SelectEmployeeServerSide <SelectEmployeeServerSide
label="Select Employee"
isMultiple={true} isMultiple={true}
isFullObject={true} isFullObject={true}
value={selectedEmployees} value={selectedEmployees}
@ -151,7 +149,7 @@ const ServiceProjectTeamAllocation = () => {
</> </>
)} )}
</div> </div>
{(selectedEmployees?.length > 0 && isManageEmployee ) && ( {selectedEmployees?.length > 0 && isManageEmployee && (
<div className="d-flex justify-content-end"> <div className="d-flex justify-content-end">
{" "} {" "}
<button <button

View File

@ -1,12 +1,103 @@
import React from 'react' import React from "react";
import Avatar from "../../common/Avatar";
import { formatUTCToLocalTime } from "../../../utils/dateUtils";
import { useServiceProjectTeam } from "../../../hooks/useServiceProject";
import { useParams } from "react-router-dom";
import { SpinnerLoader } from "../../common/Loader";
const ServiceProjectTeamList = () => { const ServiceProjectTeamList = () => {
const { projectId } = useParams();
const { data, isLoading, isError, error } = useServiceProjectTeam(
projectId,
true
);
const servceProjectColmen = [
{
key: "employeName",
label: "Name",
getValue: (e) => {
return ( return (
<div> <div className="d-flex align-itmes-center">
<Avatar />
<span>{`${e.employee.firstName} ${e.employee.lastName}`}</span>
</div> </div>
) );
} },
},
{
key: "teamRole",
label: "Role",
getValue: (e) => {
return (
<div className="d-flex align-itmes-center">
<span>{`${e.teamRole.firstName}`}</span>
</div>
);
},
},
{
key: "assignedAt",
label: "assigned Date",
getValue: (e) => {
return (
<div className="d-flex align-itmes-center">
{formatUTCToLocalTime(e.assignedAT)}
</div>
);
},
},
];
return (
<div className="data-table table-responsive ">
<table className="table w-full">
<thead>
<tr>
{servceProjectColmen.map((col) => (
<th key={col.key}>{col.label}</th>
))}
</tr>
</thead>
export default ServiceProjectTeamList <tbody>
{data?.length > 0 ? (
data.map((emp) => (
<tr key={emp?.id}>
<td className="w-min">
<div className="d-flex align-items-center gap-2 py-1">
<Avatar
size="xs"
firstName={emp?.employee?.firstName}
lastName={emp?.employee?.lastName}
/>
<span className="fw-medium">
{`${emp?.employee?.firstName} ${emp?.employee?.lastName}`}
</span>
</div>
</td>
<td>{emp?.teamRole?.name}</td>
<td>{formatUTCToLocalTime(emp.assignedAt)}</td>
</tr>
))
) : (
<tr>
<td colSpan={3} className="text-muted border-0 text-center py-4">
{isLoading ? (
<SpinnerLoader />
) : (
<div className="bg-light-secondary py-3 w-50 mx-auto my-2">
<i className="bx bx-box bx-md text-primary"></i>
<p className="fw-medium mt-3">Please Add an Employee</p>
</div>
)}
</td>
</tr>
)}
</tbody>
</table>
</div>
);
};
export default ServiceProjectTeamList;

View File

@ -150,11 +150,11 @@ const SelectEmployeeServerSide = ({
</div> </div>
{isLoading && ( {isLoading && (
<li className="dropdown-item text-muted">Loading...</li> <li className="dropdown-item text-muted text-center">Loading...</li>
)} )}
{!isLoading && options.length === 0 && ( {!isLoading && options.length === 0 && (
<li className="dropdown-item text-muted">No results found</li> <li className="dropdown-item text-muted text-center">No results found</li>
)} )}
{!isLoading && {!isLoading &&

View File

@ -140,6 +140,24 @@ export function startSignalR(loggedUser) {
) { ) {
emitters.image_gallery(); emitters.image_gallery();
} }
// --- Service Project ----------------
if (keyword === "Service_Project") {
queryClient.invalidateQueries(["serviceProjects"]);
queryClient.invalidateQueries(["serviceProject"]);
}
if (keyword === "Service_Project_Allocation") {
queryClient.invalidateQueries(["serviceProjectTeam"]);
}
if (keyword === "Job_Ticket") {
queryClient.invalidateQueries(["serviceProjectJobs"]);
queryClient.invalidateQueries(["service-job"]);
}
if (keyword === "Job_Ticket_Comment") {
queryClient.invalidateQueries(["jobComments"]);
}
}); });
connection.start(); connection.start();