added confirmation modal inside serviceproject employee list

This commit is contained in:
pramod.mahajan 2025-11-17 12:44:01 +05:30
parent 8761c128e6
commit b68f8306fd
6 changed files with 208 additions and 151 deletions

View File

@ -54,6 +54,7 @@ const ManageJob = ({ Job }) => {
isError: isJobError, isError: isJobError,
error: jobError, error: jobError,
} = useServiceProjectJobDetails(Job); } = useServiceProjectJobDetails(Job);
// const {} = useSer
const { mutate: CreateJob, isPending } = useCreateServiceProjectJob(() => { const { mutate: CreateJob, isPending } = useCreateServiceProjectJob(() => {
reset(); reset();
@ -67,7 +68,7 @@ const ManageJob = ({ Job }) => {
formData.startDate = localToUtc(formData.startDate); formData.startDate = localToUtc(formData.startDate);
formData.dueDate = localToUtc(formData.dueDate); formData.dueDate = localToUtc(formData.dueDate);
CreateJob(formData) CreateJob(formData);
}; };
useEffect(() => { useEffect(() => {
@ -80,7 +81,7 @@ const ManageJob = ({ Job }) => {
assignees: assignedEmployees, assignees: assignedEmployees,
startDate: JobData.startDate ?? null, startDate: JobData.startDate ?? null,
dueDate: JobData.dueDate ?? null, dueDate: JobData.dueDate ?? null,
tags: [], tags: JobData.tags ?? [],
}); });
}, [JobData]); }, [JobData]);
@ -102,9 +103,9 @@ const ManageJob = ({ Job }) => {
control={control} control={control}
render={({ field }) => ( render={({ field }) => (
<SelectField <SelectField
label="Project" label="Status"
options={data?.data} options={data?.data}
placeholder="Choose a Project" placeholder="Choose a Status"
required required
labelKeyKey="name" labelKeyKey="name"
valueKeyKey="id" valueKeyKey="id"
@ -121,7 +122,8 @@ const ManageJob = ({ Job }) => {
name="startDate" name="startDate"
control={control} control={control}
placeholder="DD-MM-YYYY" placeholder="DD-MM-YYYY"
className="w-full form-control-md" className="w-full"
size="md"
/> />
</div> </div>
<div className="col-12 col-md-6 mb-2 mb-md-4"> <div className="col-12 col-md-6 mb-2 mb-md-4">
@ -131,6 +133,7 @@ const ManageJob = ({ Job }) => {
minDate={watch("startDate")} minDate={watch("startDate")}
name="dueDate" name="dueDate"
className="w-full" className="w-full"
size="md"
/> />
</div> </div>
<div className="col-12 col-md-6 mb-2 mb-md-4"> <div className="col-12 col-md-6 mb-2 mb-md-4">

View File

@ -3,15 +3,9 @@ import { PROJECT_STATUS } from "../../utils/constants";
//#region Service Project //#region Service Project
export const projectSchema = z.object({ export const projectSchema = z.object({
name: z name: z.string().trim().min(1, "Name is required"),
.string()
.trim()
.min(1, "Name is required"),
shortName: z shortName: z.string().trim().min(1, "Short name is required"),
.string()
.trim()
.min(1, "Short name is required"),
clientId: z.string().trim().min(1, { message: "Client is required" }), clientId: z.string().trim().min(1, { message: "Client is required" }),
@ -38,10 +32,7 @@ export const projectSchema = z.object({
.min(7, "Invalid phone number") .min(7, "Invalid phone number")
.max(15, "Phone number too long"), .max(15, "Phone number too long"),
contactEmail: z contactEmail: z.string().trim().email("Invalid email address"),
.string()
.trim()
.email("Invalid email address"),
}); });
export const defaultProjectValues = { export const defaultProjectValues = {

View File

@ -15,17 +15,21 @@ import {
} from "../../../hooks/useServiceProject"; } from "../../../hooks/useServiceProject";
import { SpinnerLoader } from "../../common/Loader"; import { SpinnerLoader } from "../../common/Loader";
import showToast from "../../../services/toastService"; import showToast from "../../../services/toastService";
import ConfirmModal from "../../common/ConfirmModal";
const ServiceProjectTeamAllocation = () => { const ServiceProjectTeamAllocation = () => {
const { isOpen, onClose, data: Project } = useModal("ServiceTeamAllocation"); const { isOpen, onClose, data: Project } = useModal("ServiceTeamAllocation");
const [deletingId, setSeletingId] = useState(null); const [deletingEmp, setSeletingEmp] = useState({
employee: null,
isOpen: false,
});
const { const {
data: Team, data: Team,
isLoading: isTeamLoading, isLoading: isTeamLoading,
isError: isTeamError, isError: isTeamError,
error: teamError, error: teamError,
} = useServiceProjectTeam(Project?.projectId, true); } = useServiceProjectTeam(Project?.projectId, true);
const [isManageEmployee, setIsMenageEmployee] = useState(false); const [isAddEmployee, setIsAddEmployee] = useState(false);
const [nonDuplicateEmployee, setNonDuplicateEmployee] = useState([]); const [nonDuplicateEmployee, setNonDuplicateEmployee] = useState([]);
const [selectedTeam, setSelectTeam] = useState(null); const [selectedTeam, setSelectTeam] = useState(null);
const [selectedEmployees, setSelectedEmployees] = useState([]); const [selectedEmployees, setSelectedEmployees] = useState([]);
@ -44,7 +48,10 @@ const ServiceProjectTeamAllocation = () => {
const { mutate: AllocationTeam, isPending } = useAllocationServiceProjectTeam( const { mutate: AllocationTeam, isPending } = useAllocationServiceProjectTeam(
() => { () => {
setSelectedEmployees([]); setSelectedEmployees([]);
setSeletingId(null); setSeletingEmp({
employee: null,
isOpen: false,
});
} }
); );
@ -61,7 +68,6 @@ const ServiceProjectTeamAllocation = () => {
}; };
const handleDeAllocation = (emp) => { const handleDeAllocation = (emp) => {
setSeletingId(emp?.id);
let payload = [ let payload = [
{ {
projectId: Project?.projectId, projectId: Project?.projectId,
@ -76,7 +82,7 @@ const ServiceProjectTeamAllocation = () => {
useEffect(() => { useEffect(() => {
if (selectedEmployees?.length > 0 && !selectedTeam) { if (selectedEmployees?.length > 0 && !selectedTeam) {
handleRemove(selectedEmployees[0]?.id); handleRemove(selectedEmployees[0]?.id);
showToast(`Please select a first role`, "warning"); showToast(`Please select a role`, "warning");
} }
if (Team?.length > 0 && selectedEmployees?.length > 0) { if (Team?.length > 0 && selectedEmployees?.length > 0) {
setNonDuplicateEmployee((prev) => { setNonDuplicateEmployee((prev) => {
@ -103,18 +109,29 @@ const ServiceProjectTeamAllocation = () => {
}, [Team, selectedEmployees, selectedTeam]); }, [Team, selectedEmployees, selectedTeam]);
const TeamAllocationBody = ( 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=" text-start">
<div className="row"> <div className="row">
<div className="d-flex justify-content-end"> <div className="d-flex justify-content-end">
<button {!isAddEmployee && <button
className="btn btn-sm btn-primary" className="btn btn-sm btn-primary"
onClick={() => setIsMenageEmployee(!isManageEmployee)} onClick={() => setIsAddEmployee(!isAddEmployee)}
> >
<i className="bx bx-plus-circle me-2"></i>Add Employee <i className="bx bx-plus-circle me-2"></i>Add Employee
</button> </button>}
</div> </div>
{isManageEmployee && ( {isAddEmployee && (
<> <>
<div className="col-12 col-md-6 mb-3"> <div className="col-12 col-md-6 mb-3">
<SelectField <SelectField
@ -149,15 +166,24 @@ const ServiceProjectTeamAllocation = () => {
</> </>
)} )}
</div> </div>
{selectedEmployees?.length > 0 && isManageEmployee && ( { isAddEmployee && (
<div className="d-flex justify-content-end"> <div className="d-flex justify-content-end">
{" "} {" "}
<button
type="button"
className="btn btn-label-secondary btn-sm me-2"
onClick={()=>setIsAddEmployee(false)}
aria-label="Close"
disabled={isPending }
>
Cancel
</button>
<button <button
className="btn btn-sm btn-primary" className="btn btn-sm btn-primary"
disabled={isPending} disabled={isPending}
onClick={AssignEmployee} onClick={AssignEmployee}
> >
{isPending && !deletingId ? "Please wait..." : "Save"} {isPending && !deletingEmp.employee ? "Please wait..." : "Save"}
</button> </button>
</div> </div>
)} )}
@ -188,13 +214,15 @@ const ServiceProjectTeamAllocation = () => {
</td> </td>
<td>{emp?.teamRole?.name}</td> <td>{emp?.teamRole?.name}</td>
<td className=""> <td className="">
{deletingId === emp.id ? ( {deletingEmp?.emplyee?.id === emp.id && isPending ? (
<div className="spinner-border spinner-border-sm "></div> <div className="spinner-border spinner-border-sm "></div>
) : ( ) : (
<span disabled={isPending}> <span disabled={isPending}>
<i <i
className="bx bx-trash bx-sm text-danger cursor-pointer" className="bx bx-trash bx-sm text-danger cursor-pointer"
onClick={() => handleDeAllocation(emp)} onClick={() =>
setSeletingEmp({ employee: emp, isOpen: true })
}
></i> ></i>
</span> </span>
)} )}
@ -212,7 +240,10 @@ const ServiceProjectTeamAllocation = () => {
) : ( ) : (
<div className="bg-light-secondary py-3 w-50 m-auto my-2"> <div className="bg-light-secondary py-3 w-50 m-auto my-2">
<i className="bx bx-box bx-md text-primary"></i> <i className="bx bx-box bx-md text-primary"></i>
<p className="fw-medium mt-3"> Please Add a Employee </p> <p className="fw-medium mt-3">
{" "}
Please Add a Employee{" "}
</p>
</div> </div>
)} )}
</td> </td>
@ -222,6 +253,7 @@ const ServiceProjectTeamAllocation = () => {
</table> </table>
</div> </div>
</div> </div>
</>
); );
return ( return (

View File

@ -4,6 +4,7 @@ import { useController } from "react-hook-form";
const DatePicker = ({ const DatePicker = ({
name, name,
control, control,
size="sm",
placeholder = "DD-MM-YYYY", placeholder = "DD-MM-YYYY",
className = "", className = "",
allowText = false, allowText = false,
@ -51,7 +52,7 @@ const DatePicker = ({
<div className={`position-relative ${className} w-max `}> <div className={`position-relative ${className} w-max `}>
<input <input
type="text" type="text"
className="form-control form-control form-control-sm" className={`form-control form-control form-control-${size}`}
placeholder={placeholder} placeholder={placeholder}
value={displayValue} value={displayValue}
onChange={(e) => { onChange={(e) => {

View File

@ -1,4 +1,4 @@
import { useEffect, useState } from "react"; import { useEffect, useState,useCallback } from "react";
import { cacheData, getCachedData } from "../slices/apiDataManager"; import { cacheData, getCachedData } from "../slices/apiDataManager";
import { RolesRepository } from "../repositories/MastersRepository"; import { RolesRepository } from "../repositories/MastersRepository";
import EmployeeRepository from "../repositories/EmployeeRepository"; import EmployeeRepository from "../repositories/EmployeeRepository";
@ -9,6 +9,36 @@ import { useSelector } from "react-redux";
import { store } from "../store/store"; import { store } from "../store/store";
import { queryClient } from "../layouts/AuthLayout"; import { queryClient } from "../layouts/AuthLayout";
export const useUserCache = () => {
const [userCache, setUserCache] = useState({});
const addToCache = (id, user) => {
setUserCache((prev) => ({ ...prev, [id]: user }));
};
const getUser = async (id) => {
if (userCache[id]) return userCache[id];
try {
const res = await EmployeeRepository.getEmployeeProfile(id);
if (res?.data) {
addToCache(id, res.data);
return res.data;
}
} catch (err) {
console.error("User not found", id);
return null;
}
};
return {
userCache,
getUser,
addToCache,
};
};
// Query --------------------------------------------------------------------------- // Query ---------------------------------------------------------------------------
export const useEmployee = (employeeId) => { export const useEmployee = (employeeId) => {
@ -342,25 +372,25 @@ export const useUpdateEmployeeRoles = ({
}; };
}; };
export const useOrganizationHierarchy = (employeeId) => {
export const useOrganizationHierarchy=(employeeId)=>{ return useQuery({
return useQuery({ queryKey: ["organizationHierarchy", employeeId],
queryKey:["organizationHierarchy",employeeId], queryFn: async () => {
queryFn:async()=> {
const resp = await EmployeeRepository.getOrganizaionHierarchy(employeeId); const resp = await EmployeeRepository.getOrganizaionHierarchy(employeeId);
return resp.data; return resp.data;
}, },
enabled:!!employeeId enabled: !!employeeId,
}) });
} };
export const useManageEmployeeHierarchy = (employeeId, onSuccessCallBack) => { export const useManageEmployeeHierarchy = (employeeId, onSuccessCallBack) => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
return useMutation({ return useMutation({
mutationFn: async (payload) => { mutationFn: async (payload) => {
return await EmployeeRepository.manageOrganizationHierarchy(employeeId, payload); return await EmployeeRepository.manageOrganizationHierarchy(
employeeId,
payload
);
}, },
onSuccess: (_, variables) => { onSuccess: (_, variables) => {
queryClient.invalidateQueries({ queryClient.invalidateQueries({

View File

@ -132,7 +132,7 @@ export const useAllocationServiceProjectTeam = (onSuccessCallback) => {
"success" "success"
); );
} else { } else {
showToast(`Employee DeAllocated successfully`, "success"); showToast(`Employee removed successfully`, "success");
} }
}, },
onError: (error) => { onError: (error) => {