add new EmployeeSearch for multiple
This commit is contained in:
parent
92bcfb73c6
commit
7e646ca3e8
@ -5,21 +5,24 @@ import { useAuthModal, useModal } from "./hooks/useAuth";
|
||||
import SwitchTenant from "./pages/authentication/SwitchTenant";
|
||||
import ChangePasswordPage from "./pages/authentication/ChangePassword";
|
||||
import NewCollection from "./components/collections/ManageCollection";
|
||||
import ServiceProjectTeamAllocation from "./components/ServiceProject/ServiceProjectTeam/ServiceProjectTeamAllocation";
|
||||
|
||||
const ModalProvider = () => {
|
||||
const { isOpen, onClose } = useOrganizationModal();
|
||||
const { isOpen: isAuthOpen } = useAuthModal();
|
||||
const {isOpen:isChangePass} = useModal("ChangePassword")
|
||||
const {isOpen:isCollectionNew} = useModal("newCollection");
|
||||
const { isOpen: isChangePass } = useModal("ChangePassword");
|
||||
const { isOpen: isCollectionNew } = useModal("newCollection");
|
||||
const { isOpen: isServiceTeamAllocation } = useModal("ServiceTeamAllocation");
|
||||
|
||||
return (
|
||||
<>
|
||||
{isOpen && <OrganizationModal />}
|
||||
{isAuthOpen && <SwitchTenant />}
|
||||
{isChangePass && <ChangePasswordPage /> }
|
||||
{isCollectionNew && <NewCollection/>}
|
||||
{isChangePass && <ChangePasswordPage />}
|
||||
{isCollectionNew && <NewCollection />}
|
||||
{isServiceTeamAllocation && <ServiceProjectTeamAllocation />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModalProvider;
|
||||
export default ModalProvider;
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
import React from 'react'
|
||||
import { useModal } from '../../../hooks/useAuth'
|
||||
|
||||
|
||||
const ProjectTeam = () => {
|
||||
const {onOpen} = useModal("ServiceTeamAllocation");
|
||||
|
||||
return (
|
||||
<div className='card page-min-h mt-2'>
|
||||
<div className='row text-end'>
|
||||
<div className='col-12'>
|
||||
<div className='p-2'><button onClick={onOpen} className='btn btn-sm btn-primary'><i className='bx bx-plus-circle me-2'></i>Assign Employee</button></div>
|
||||
</div>
|
||||
</div>
|
||||
{/* <ServiceProjectTeamList/> */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ProjectTeam
|
||||
@ -0,0 +1,52 @@
|
||||
import React, { 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";
|
||||
|
||||
const ServiceProjectTeamAllocation = () => {
|
||||
const { isOpen, onClose } = useModal("ServiceTeamAllocation");
|
||||
const [selectedTeam, setSelectTeam] = useState(null);
|
||||
const [selectedEmployees, setSelectedEmployees] = useState(null);
|
||||
const { data, isLoading, isError, error } = useTeamRole();
|
||||
console.log(selectedEmployees);
|
||||
const TeamAllocation = (
|
||||
<div className="row text-start">
|
||||
<div className="col-6">
|
||||
<SelectField
|
||||
label="Select Team"
|
||||
required
|
||||
options={data}
|
||||
value={selectedTeam}
|
||||
labelKey="name"
|
||||
valueKey="id"
|
||||
valueKey="name"
|
||||
onChange={(e) => setSelectTeam(e)}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-6">
|
||||
<SelectEmployeeServerSide
|
||||
isMultiple={true}
|
||||
isFullObject={true}
|
||||
value={selectedEmployees}
|
||||
onChange={setSelectedEmployees}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<Modal
|
||||
size="lg"
|
||||
title={"Team Allocation"}
|
||||
isOpen={isOpen}
|
||||
onClose={onClose}
|
||||
body={TeamAllocation}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ServiceProjectTeamAllocation;
|
||||
@ -0,0 +1,12 @@
|
||||
import React from 'react'
|
||||
|
||||
const ServiceProjectTeamList = () => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ServiceProjectTeamList
|
||||
@ -1,44 +1,108 @@
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import Label from "../Label";
|
||||
import { useDebounce } from "../../../utils/appUtils";
|
||||
import { useEmployeesName } from "../../../hooks/useEmployees";
|
||||
|
||||
const SelectFieldServerSide = ({
|
||||
const SelectEmployeeServerSide = ({
|
||||
label = "Select",
|
||||
options = [],
|
||||
placeholder = "Select Option",
|
||||
placeholder = "Select Employee",
|
||||
required = false,
|
||||
value,
|
||||
value = null,
|
||||
onChange,
|
||||
valueKey = "id",
|
||||
labelKey = "name",
|
||||
isLoading = false,
|
||||
isFullObject = false,
|
||||
isMultiple = false,
|
||||
projectId = null,
|
||||
isAllEmployee = false,
|
||||
}) => {
|
||||
const [searchText,setSeachText] = useState("")
|
||||
const debounce = useDebounce(searchText,300);
|
||||
// const {} = use
|
||||
const [searchText, setSearchText] = useState("");
|
||||
const debounce = useDebounce(searchText, 300);
|
||||
|
||||
const { data, isLoading } = useEmployeesName(
|
||||
projectId,
|
||||
debounce,
|
||||
isAllEmployee
|
||||
);
|
||||
|
||||
const options = data?.data ?? [];
|
||||
const [open, setOpen] = useState(false);
|
||||
const dropdownRef = useRef(null);
|
||||
|
||||
const getDisplayName = (emp) => {
|
||||
if (!emp) return "";
|
||||
return `${emp.firstName || ""} ${emp.lastName || ""}`.trim();
|
||||
};
|
||||
|
||||
/** -----------------------------
|
||||
* SELECTED OPTION (SINGLE)
|
||||
* ----------------------------- */
|
||||
let selectedSingle = null;
|
||||
|
||||
if (!isMultiple) {
|
||||
if (isFullObject && value) selectedSingle = value;
|
||||
else if (!isFullObject && value)
|
||||
selectedSingle = options.find((o) => o[valueKey] === value);
|
||||
}
|
||||
|
||||
/** -----------------------------
|
||||
* SELECTED OPTION (MULTIPLE)
|
||||
* ----------------------------- */
|
||||
let selectedList = [];
|
||||
|
||||
if (isMultiple && Array.isArray(value)) {
|
||||
if (isFullObject) selectedList = value;
|
||||
else {
|
||||
selectedList = options.filter((opt) => value.includes(opt[valueKey]));
|
||||
}
|
||||
}
|
||||
|
||||
/** Main button label */
|
||||
const displayText = !isMultiple
|
||||
? getDisplayName(selectedSingle) || placeholder
|
||||
: selectedList.length > 0
|
||||
? selectedList.map((e) => getDisplayName(e)).join(", ")
|
||||
: placeholder;
|
||||
|
||||
/** -----------------------------
|
||||
* HANDLE OUTSIDE CLICK
|
||||
* ----------------------------- */
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event) => {
|
||||
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
||||
const handleClickOutside = (e) => {
|
||||
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
||||
setOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
return () => document.removeEventListener("mousedown", handleClickOutside);
|
||||
}, []);
|
||||
|
||||
const selectedOption = options.find((opt) => opt[valueKey] === value);
|
||||
|
||||
const displayText = selectedOption ? selectedOption[labelKey] : placeholder;
|
||||
|
||||
/** -----------------------------
|
||||
* HANDLE SELECT
|
||||
* ----------------------------- */
|
||||
const handleSelect = (option) => {
|
||||
onChange(option[valueKey]);
|
||||
setOpen(false);
|
||||
};
|
||||
if (!isMultiple) {
|
||||
// SINGLE SELECT
|
||||
if (isFullObject) onChange(option);
|
||||
else onChange(option[valueKey]);
|
||||
} else {
|
||||
// MULTIPLE SELECT
|
||||
let updated = [];
|
||||
|
||||
const toggleDropdown = () => setOpen((prev) => !prev);
|
||||
const exists = selectedList.some((e) => e[valueKey] === option[valueKey]);
|
||||
|
||||
if (exists) {
|
||||
// remove
|
||||
updated = selectedList.filter((e) => e[valueKey] !== option[valueKey]);
|
||||
} else {
|
||||
// add
|
||||
updated = [...selectedList, option];
|
||||
}
|
||||
|
||||
if (isFullObject) onChange(updated);
|
||||
else onChange(updated.map((x) => x[valueKey]));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mb-3 position-relative" ref={dropdownRef}>
|
||||
@ -48,22 +112,21 @@ const SelectFieldServerSide = ({
|
||||
</Label>
|
||||
)}
|
||||
|
||||
{/* MAIN BUTTON */}
|
||||
<button
|
||||
type="button"
|
||||
className={`select2-icons form-select d-flex align-items-center justify-content-between ${
|
||||
open ? "show" : ""
|
||||
}`}
|
||||
onClick={toggleDropdown}
|
||||
disabled={isLoading}
|
||||
onClick={() => setOpen((prev) => !prev)}
|
||||
>
|
||||
<span
|
||||
className={`text-truncate ${!selectedOption ? "text-muted" : ""}`}
|
||||
>
|
||||
{isLoading ? "Loading..." : displayText}
|
||||
<span className={`text-truncate ${!displayText ? "text-muted" : ""}`}>
|
||||
{displayText}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
{open && !isLoading && (
|
||||
{/* DROPDOWN */}
|
||||
{open && (
|
||||
<ul
|
||||
className="dropdown-menu w-100 shadow-sm show animate__fadeIn"
|
||||
style={{
|
||||
@ -76,23 +139,47 @@ const SelectFieldServerSide = ({
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
{options.map((option, i) => (
|
||||
<li key={i}>
|
||||
<button
|
||||
type="button"
|
||||
className={`dropdown-item ${
|
||||
option[valueKey] === value ? "active" : ""
|
||||
}`}
|
||||
onClick={() => handleSelect(option)}
|
||||
>
|
||||
{option[labelKey]}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
<div className="p-1">
|
||||
<input
|
||||
type="search"
|
||||
value={searchText}
|
||||
onChange={(e) => setSearchText(e.target.value)}
|
||||
className="form-control form-control-sm"
|
||||
placeholder="Search..."
|
||||
/>
|
||||
</div>
|
||||
|
||||
{isLoading && (
|
||||
<li className="dropdown-item text-muted">Loading...</li>
|
||||
)}
|
||||
|
||||
{!isLoading && options.length === 0 && (
|
||||
<li className="dropdown-item text-muted">No results found</li>
|
||||
)}
|
||||
|
||||
{!isLoading &&
|
||||
options.map((option) => {
|
||||
const isActive = isMultiple
|
||||
? selectedList.some((x) => x[valueKey] === option[valueKey])
|
||||
: selectedSingle &&
|
||||
selectedSingle[valueKey] === option[valueKey];
|
||||
|
||||
return (
|
||||
<li key={option[valueKey]}>
|
||||
<button
|
||||
type="button"
|
||||
className={`dropdown-item ${isActive ? "active" : ""}`}
|
||||
onClick={() => handleSelect(option)}
|
||||
>
|
||||
{getDisplayName(option)}
|
||||
</button>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectFieldServerSide;
|
||||
export default SelectEmployeeServerSide;
|
||||
|
||||
@ -40,7 +40,7 @@ const Modal = ({
|
||||
</div>
|
||||
|
||||
{/* Body */}
|
||||
<div className="modal-body pt-0">{body}</div>
|
||||
<div className="modal-body pt-0 text-black">{body}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -296,6 +296,25 @@ export const useOrganizationType = () => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useJobStatus=()=>{
|
||||
return useQuery({
|
||||
queryKey:["Job_Staus"],
|
||||
queryFn:async()=>{
|
||||
const resp = await MasterRespository.getJobStatus();
|
||||
return resp.data;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const useTeamRole=()=>{
|
||||
return useQuery({
|
||||
queryKey:["Team_Role"],
|
||||
queryFn:async()=>{
|
||||
const resp = await MasterRespository.getTeamRole();
|
||||
return resp.data;
|
||||
}
|
||||
})
|
||||
}
|
||||
//#region ==Get Masters==
|
||||
const fetchMasterData = async (masterType) => {
|
||||
switch (masterType) {
|
||||
@ -385,6 +404,8 @@ const useMaster = () => {
|
||||
export default useMaster;
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
// ================================Mutation====================================
|
||||
|
||||
//#region Job Role
|
||||
@ -435,6 +456,9 @@ export const useCreateJobRole = (onSuccessCallback) => {
|
||||
//#endregion Job Role
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//#region Application Role
|
||||
export const useCreateApplicationRole = (onSuccessCallback) => {
|
||||
const queryClient = useQueryClient();
|
||||
@ -480,6 +504,10 @@ export const useUpdateApplicationRole = (onSuccessCallback) => {
|
||||
};
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//#region Create work Category
|
||||
export const useCreateWorkCategory = (onSuccessCallback) => {
|
||||
const queryClient = useQueryClient();
|
||||
@ -525,6 +553,11 @@ export const useUpdateWorkCategory = (onSuccessCallback) => {
|
||||
};
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//#region Contact Category
|
||||
|
||||
export const useCreateContactCategory = (onSuccessCallback) => {
|
||||
@ -575,6 +608,10 @@ export const useUpdateContactCategory = (onSuccessCallback) => {
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//#region Contact Tag
|
||||
|
||||
export const useCreateContactTag = (onSuccessCallback) => {
|
||||
@ -621,6 +658,10 @@ export const useUpdateContactTag = (onSuccessCallback) => {
|
||||
};
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//#region Expense Category
|
||||
export const useCreateExpenseCategory = (onSuccessCallback) => {
|
||||
const queryClient = useQueryClient();
|
||||
@ -666,6 +707,11 @@ export const useUpdateExpenseCategory = (onSuccessCallback) => {
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//#region Payment Mode
|
||||
|
||||
export const useCreatePaymentMode = (onSuccessCallback) => {
|
||||
@ -712,6 +758,10 @@ export const useUpdatePaymentMode = (onSuccessCallback) => {
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Services-------------------------------
|
||||
|
||||
// export const useCreateService = (onSuccessCallback) => {
|
||||
@ -793,6 +843,10 @@ export const useUpdateService = (onSuccessCallback) => {
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//#region Activity Grouph
|
||||
|
||||
export const useCreateActivityGroup = (onSuccessCallback) => {
|
||||
@ -857,6 +911,10 @@ export const useUpdateActivityGroup = (onSuccessCallback) => {
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//#region Activities
|
||||
export const useCreateActivity = (onSuccessCallback) => {
|
||||
const queryClient = useQueryClient();
|
||||
@ -911,6 +969,11 @@ export const useUpdateActivity = (onSuccessCallback) => {
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//#region Expense Status
|
||||
export const useCreateExpenseStatus = (onSuccessCallback) => {
|
||||
const queryClient = useQueryClient();
|
||||
@ -954,6 +1017,10 @@ export const useUpdateExpenseStatus = (onSuccessCallback) => {
|
||||
};
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//#region Document-Category
|
||||
export const useCreateDocumentCatgory = (onSuccessCallback) => {
|
||||
const queryClient = useQueryClient();
|
||||
@ -1000,6 +1067,11 @@ export const useUpdateDocumentCategory = (onSuccessCallback) => {
|
||||
};
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//#region Document-Type
|
||||
export const useCreateDocumentType = (onSuccessCallback) => {
|
||||
const queryClient = useQueryClient();
|
||||
@ -1044,6 +1116,10 @@ export const useUpdateDocumentType = (onSuccessCallback) => {
|
||||
};
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//#region Payment Adjustment Head
|
||||
export const useCreatePaymentAjustmentHead = (onSuccessCallback) => {
|
||||
const queryClient = useQueryClient();
|
||||
@ -1087,6 +1163,10 @@ export const useUpdatePaymentAjustmentHead = (onSuccessCallback) => {
|
||||
};
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//#region ==Delete Master==
|
||||
export const useDeleteMasterItem = () => {
|
||||
const queryClient = useQueryClient();
|
||||
@ -1122,6 +1202,8 @@ export const useDeleteMasterItem = () => {
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
export const useDeleteServiceGroup = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
|
||||
@ -103,6 +103,26 @@ export const useActiveInActiveServiceProject = (onSuccessCallback) => {
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useAllocationTeam=()=>{
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn:async(paylaod)=> await ServiceProjectRepository.AllocateEmployee(paylaod),
|
||||
onSuccess: (data, variables) => {
|
||||
// queryClient.invalidateQueries({ queryKey: ["serviceProjects"] });
|
||||
if (onSuccessCallback) onSuccessCallback();
|
||||
showToast(`${variables?.length} employee allocated successfully`, "success");
|
||||
},
|
||||
onError: (error) => {
|
||||
showToast(
|
||||
error?.response?.data?.message ||
|
||||
error.message ||
|
||||
"Failed to update project",
|
||||
"error"
|
||||
);
|
||||
},
|
||||
})
|
||||
}
|
||||
//#endregion
|
||||
|
||||
//#region Service Jobs
|
||||
|
||||
@ -4,6 +4,7 @@ import ServiceProjectNav from "../../components/ServiceProject/ServiceProjectNav
|
||||
import { ComingSoonPage } from "../Misc/ComingSoonPage";
|
||||
import ServiceProjectProfile from "../../components/ServiceProject/ServiceProjectProfile";
|
||||
import Jobs from "../../components/ServiceProject/Jobs";
|
||||
import ProjectTeam from "../../components/ServiceProject/ServiceProjectTeam/ProjectTeam";
|
||||
|
||||
const ServiceProjectDetail = () => {
|
||||
const [activePill, setActivePill] = useState(
|
||||
@ -17,6 +18,8 @@ const ServiceProjectDetail = () => {
|
||||
switch (activePill) {
|
||||
case "profile":
|
||||
return <ServiceProjectProfile />;
|
||||
case "teams":
|
||||
return <ProjectTeam />;
|
||||
case "jobs":
|
||||
return <Jobs />;
|
||||
default:
|
||||
|
||||
@ -149,5 +149,9 @@ export const MasterRespository = {
|
||||
|
||||
getCurrencies: () => api.get(`/api/Master/currencies/list`),
|
||||
|
||||
getRecurringStatus:()=>api.get(`/api/Master/recurring-status/list`)
|
||||
getRecurringStatus: () => api.get(`/api/Master/recurring-status/list`),
|
||||
|
||||
getJobStatus: () => api.get("/api/Master/job-status/list"),
|
||||
|
||||
getTeamRole:()=> api.get(`/api/Master/team-roles/list`),
|
||||
};
|
||||
|
||||
@ -11,7 +11,7 @@ export const ServiceProjectRepository = {
|
||||
api.put(`/api/ServiceProject/edit/${id}`, data),
|
||||
DeleteServiceProject: (id, isActive = false) =>
|
||||
api.delete(`/api/ServiceProject/delete/${id}?isActive=${isActive}`),
|
||||
|
||||
AllocateEmployee: (data) => api.post(`/api/ServiceProject/manage/allocation`),
|
||||
//#region Job
|
||||
|
||||
CreateJob: (data) => api.post(`/api/ServiceProject/job/create`, data),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user