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 { useServiceProjectJobContext } from "./Jobs";
const JobList = ({ filterByProject }) => {
const JobList = () => {
const { setSelectedJob, setManageJob } = useServiceProjectJobContext();
const { id } = useParams();
const { projectId } = useParams();
const { data, isLoading, isError, error } = useServiceProjectJobs(
ITEMS_PER_PAGE,
1,
true,
filterByProject ?? id
projectId
);
const jobGrid = [

View File

@ -2,55 +2,53 @@ import React from "react";
import Avatar from "../common/Avatar";
const JobStatusLog = ({ data }) => {
console.log(data)
console.log(data);
return (
<div className="card shadow-none p-0">
<div className="card-body p-0">
<div className="list-group">
{data?.map((item) => (
<div
key={item.id}
className="list-group-item border-0 border-bottom p-1"
>
<div className="d-flex justify-content-between">
<div
key={item.id}
className="list-group-item border-0 border-bottom p-1"
>
<div className="d-flex justify-content-between">
<div>
<span className="fw-semibold">
{item.nextStatus?.displayName ?? item.status?.displayName ?? "Status"}
{item.nextStatus?.displayName ??
item.status?.displayName ??
"Status"}
</span>
</div>
<span className="badge bg-primary">
{/* <span className="badge bg-primary">
Level {item.nextStatus?.level ?? item.status?.level}
</span>
</span> */}
</div>
<div className="d-flex align-items-start mt-2 mx-0 px-0">
<Avatar
firstName={item.updatedBy?.firstName}
lastName={item.updatedBy?.lastName}
/>
<div className="">
<div className="d-flex flex-row gap-3">
<span className="fw-semibold">
{item.updatedBy?.firstName} {item.updatedBy?.lastName}
</span>
<span className="text-secondary">
{/* <em>{formatUTCToLocalTime(item?.createdAt, true)}</em> */}
</span>
</div>
<div className="text-muted text-secondary">
{item?.updatedBy?.jobRoleName}
</div>
<div className="text-wrap">
<p className="mb-1 mt-2 text-muted">{item.comment}</p>
</div>
<div className="d-flex align-items-start mt-2 mx-0 px-0">
<Avatar
firstName={item.updatedBy?.firstName}
lastName={item.updatedBy?.lastName}
/>
<div className="">
<div className="d-flex flex-row gap-3">
<span className="fw-semibold">
{item.updatedBy?.firstName} {item.updatedBy?.lastName}
</span>
<span className="text-secondary">
{/* <em>{formatUTCToLocalTime(item?.createdAt, true)}</em> */}
</span>
</div>
<div className="text-muted text-secondary">
{item?.updatedBy?.jobRoleName}
</div>
<div className="text-wrap">
<p className="mb-1 mt-2 text-muted">{item.comment}</p>
</div>
</div>
</div>
</div>
))}
</div>
</div>
</div>

View File

@ -16,7 +16,7 @@ const ManageJobTicket = ({ Job }) => {
const tabsData = [
{
id: "comment",
title: "Coments",
title: "Comments",
icon:"bx bx-comment me-2",
active: true,
content: <JobComments data={data} />,
@ -58,7 +58,7 @@ const ManageJobTicket = ({ Job }) => {
</span>{" "}
<i className="bx bx-right-arrow-alt"></i>{" "}
<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>
</div>
<div className="d-block mt-2">
@ -71,9 +71,9 @@ const ManageJobTicket = ({ Job }) => {
firstName={data?.createdBy?.firstName}
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>
<small className="text-secondary">{data?.createdBy?.jobRoleName}</small>
<small className="text-secondary ms-1">({data?.createdBy?.jobRoleName})</small>
</div>
</div>
<div className="d-flex align-items-center">
@ -84,9 +84,9 @@ const ManageJobTicket = ({ Job }) => {
{data?.assignees?.map((emp)=>(
<div className="d-flex flex-row ">
<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>
<small className="text-secondary">{emp.jobRoleName}</small>
<small className="text-secondary ms-1">( {emp.jobRoleName} )</small>
</div>
</div>
))}

View File

@ -1,6 +1,7 @@
import React from 'react'
import { useModal } from '../../../hooks/useAuth'
import { useParams } from 'react-router-dom';
import ServiceProjectTeamList from './ServiceProjectTeamList';
const ProjectTeam = () => {
@ -8,13 +9,13 @@ const {onOpen} = useModal("ServiceTeamAllocation");
const {projectId}= useParams();
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='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>
{/* <ServiceProjectTeamList/> */}
<ServiceProjectTeamList/>
</div>
)
}

View File

@ -57,7 +57,7 @@ const ServiceProjectTeamAllocation = () => {
isActive: true,
};
});
AllocationTeam({ payload, isActive: true });
AllocationTeam({ payload, isActive: true });
};
const handleDeAllocation = (emp) => {
@ -71,16 +71,13 @@ const ServiceProjectTeamAllocation = () => {
},
];
AllocationTeam({payload:payload,isActive:false});
AllocationTeam({ payload: payload, isActive: false });
};
useEffect(() => {
if(selectedEmployees?.length > 0 && !selectedTeam){
handleRemove(selectedEmployees[0]?.id)
showToast(
`Please select a first role`,
"warning"
);
}
if (selectedEmployees?.length > 0 && !selectedTeam) {
handleRemove(selectedEmployees[0]?.id);
showToast(`Please select a first role`, "warning");
}
if (Team?.length > 0 && selectedEmployees?.length > 0) {
setNonDuplicateEmployee((prev) => {
let updated = [...prev];
@ -113,7 +110,7 @@ const ServiceProjectTeamAllocation = () => {
className="btn btn-sm btn-primary"
onClick={() => setIsMenageEmployee(!isManageEmployee)}
>
Manage Employee
<i className="bx bx-plus-circle me-2"></i>Add Employee
</button>
</div>
@ -137,6 +134,7 @@ const ServiceProjectTeamAllocation = () => {
<div className="col-12 col-md-6 mb-3">
<SelectEmployeeServerSide
label="Select Employee"
isMultiple={true}
isFullObject={true}
value={selectedEmployees}
@ -151,7 +149,7 @@ const ServiceProjectTeamAllocation = () => {
</>
)}
</div>
{(selectedEmployees?.length > 0 && isManageEmployee ) && (
{selectedEmployees?.length > 0 && isManageEmployee && (
<div className="d-flex justify-content-end">
{" "}
<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 { projectId } = useParams();
const { data, isLoading, isError, error } = useServiceProjectTeam(
projectId,
true
);
const servceProjectColmen = [
{
key: "employeName",
label: "Name",
getValue: (e) => {
return (
<div className="d-flex align-itmes-center">
<Avatar />
<span>{`${e.employee.firstName} ${e.employee.lastName}`}</span>
</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>
</div>
)
}
<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>
{isLoading && (
<li className="dropdown-item text-muted">Loading...</li>
<li className="dropdown-item text-muted text-center">Loading...</li>
)}
{!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 &&

View File

@ -140,6 +140,24 @@ export function startSignalR(loggedUser) {
) {
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();