marco.pms.web/src/components/ServiceProject/ServiceProjectTeam/ServiceProjectTeamAllocation.jsx
2025-11-18 16:56:11 +05:30

268 lines
8.3 KiB
JavaScript

import React, { useEffect, useState } from "react";
import { useModal } from "../../../hooks/useAuth";
import Modal from "../../common/Modal";
import Label from "../../common/Label";
import { useTeamRole } from "../../../hooks/masterHook/useMaster";
import SelectField from "../../common/Forms/SelectField";
import SelectFieldServerSide from "../../common/Forms/SelectFieldServerSide";
import SelectEmployeeServerSide from "../../common/Forms/SelectFieldServerSide";
import Avatar from "../../common/Avatar";
import { useParams } from "react-router-dom";
import { EmployeeChip } from "../../common/Chips";
import {
useAllocationServiceProjectTeam,
useServiceProjectTeam,
} from "../../../hooks/useServiceProject";
import { SpinnerLoader } from "../../common/Loader";
import showToast from "../../../services/toastService";
import ConfirmModal from "../../common/ConfirmModal";
const ServiceProjectTeamAllocation = () => {
const { isOpen, onClose, data: Project } = useModal("ServiceTeamAllocation");
const [deletingEmp, setSeletingEmp] = useState({
employee: null,
isOpen: false,
});
const {
data: Team,
isLoading: isTeamLoading,
isError: isTeamError,
error: teamError,
} = useServiceProjectTeam(Project?.projectId, true);
const [isAddEmployee, setIsAddEmployee] = useState(false);
const [nonDuplicateEmployee, setNonDuplicateEmployee] = useState([]);
const [selectedTeam, setSelectTeam] = useState(null);
const [selectedEmployees, setSelectedEmployees] = useState([]);
const { data, isLoading } = useTeamRole();
const TeamAllocationColumns = [
{
key: "team",
label: "Role",
getValue: (e) => e?.teamName || "-",
},
];
const handleRemove = (id) => {
setSelectedEmployees((prev) => prev.filter((e) => e.id !== id));
};
const { mutate: AllocationTeam, isPending } = useAllocationServiceProjectTeam(
() => {
setSelectedEmployees([]);
setSeletingEmp({
employee: null,
isOpen: false,
});
}
);
const AssignEmployee = () => {
let payload = selectedEmployees.map((e) => {
return {
projectId: Project?.projectId,
employeeId: e.id,
teamRoleId: selectedTeam,
isActive: true,
};
});
AllocationTeam({ payload, isActive: true });
};
const handleDeAllocation = (emp) => {
let payload = [
{
projectId: Project?.projectId,
employeeId: emp.employee.id,
teamRoleId: emp.teamRole.id,
isActive: false,
},
];
AllocationTeam({ payload: payload, isActive: false });
};
useEffect(() => {
if (selectedEmployees?.length > 0 && !selectedTeam) {
handleRemove(selectedEmployees[0]?.id);
showToast(`Please select a role`, "warning");
}
if (Team?.length > 0 && selectedEmployees?.length > 0) {
setNonDuplicateEmployee((prev) => {
let updated = [...prev];
selectedEmployees.forEach((selectedEmployee) => {
const alreadyAllocated = Team.some(
(e) =>
e?.employee?.id === selectedEmployee?.id &&
e?.teamRole?.id === selectedTeam
);
if (alreadyAllocated) {
handleRemove(selectedEmployee?.id);
showToast(
`${selectedEmployee.firstName} ${selectedEmployee.lastName} already allocated with same role`,
"warning"
);
}
});
return updated;
});
}
}, [Team, selectedEmployees, selectedTeam]);
const TeamAllocationBody = (
<>
<ConfirmModal
type="delete"
header="Remove Employee"
message="Are you sure you want remove?"
onSubmit={handleDeAllocation}
onClose={() => setSeletingEmp({ employee: null, isOpen: false })}
loading={isPending}
paramData={deletingEmp.employee}
isOpen={deletingEmp.isOpen}
/>
<div className=" text-start">
<div className="row">
<div className="d-flex justify-content-end">
{!isAddEmployee && (
<button
className="btn btn-sm btn-primary"
onClick={() => setIsAddEmployee(!isAddEmployee)}
>
<i className="bx bx-plus-circle me-2"></i>Add Employee
</button>
)}
</div>
{isAddEmployee && (
<>
<div className="col-12 col-md-6 mb-3">
<SelectField
label="Select Role"
required
options={data}
value={selectedTeam}
labelKey="name"
valueKey="id"
onChange={(e) => {
setSelectedEmployees([]);
setSelectTeam(e);
}}
isLoading={isLoading}
/>
</div>
<div className="col-12 col-md-6 mb-3">
<SelectEmployeeServerSide
label="Select Employee"
isMultiple={true}
isFullObject={true}
value={selectedEmployees}
onChange={setSelectedEmployees}
/>
</div>
<div className="col-12 d-flex flex-row gap-2 flex-wrap">
{selectedEmployees.map((e) => (
<EmployeeChip handleRemove={handleRemove} employee={e} />
))}
</div>
</>
)}
</div>
{isAddEmployee && (
<div className="d-flex justify-content-end my-2">
{" "}
<button
type="button"
className="btn btn-label-secondary btn-sm me-2"
onClick={() => setIsAddEmployee(false)}
aria-label="Close"
disabled={isPending}
>
Cancel
</button>
<button
className="btn btn-sm btn-primary"
disabled={isPending}
onClick={AssignEmployee}
>
{isPending && !deletingEmp.employee ? "Please wait..." : "Save"}
</button>
</div>
)}
<div className="col-12">
<table className="table text-center">
<thead>
<tr>
<th>Name</th>
<th>Role</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{Team?.length > 0 ? (
Team?.map((emp) => (
<tr key={emp?.id}>
<td className="w-min">
<div className="d-flex align-items-center gap-2">
<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>
{deletingEmp?.employee?.id === emp.id && isPending ? (
<div className="spinner-border spinner-border-sm"></div>
) : (
<i
className="bx bx-trash bx-sm text-danger cursor-pointer"
onClick={() =>
setSeletingEmp({ employee: emp, isOpen: true })
}
></i>
)}
</td>
</tr>
))
) : (
<tr>
<td
colSpan={3}
className="text-center text-muted py-4 border-0"
>
{isTeamLoading ? (
<SpinnerLoader />
) : (
<p className="m-0 py-4">No Records Found</p>
)}
</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
</>
);
return (
<Modal
size="lg"
title={"Team Allocation"}
isOpen={isOpen}
onClose={onClose}
body={TeamAllocationBody}
/>
);
};
export default ServiceProjectTeamAllocation;