buckets can assign employee
This commit is contained in:
parent
16301def0c
commit
b02c599130
@ -1,25 +1,57 @@
|
||||
import React, { useState } from "react";
|
||||
import { useSortableData } from "../../hooks/useSortableData";
|
||||
|
||||
const EmployeeList = ({ employees }) => {
|
||||
const [selectedIds, setSelectedIds] = useState([]);
|
||||
import React,{useState,useEffect} from 'react'
|
||||
import {useSortableData} from '../../hooks/useSortableData';
|
||||
const EmployeeList = ( {employees, onChange, assignedEmployee = []} ) =>
|
||||
{
|
||||
const [employeefiltered, setEmployeeFilter] = useState([]);
|
||||
const [employeeStatusList, setEmployeeStatusList] = useState([]);
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
// Populate filtered list on load
|
||||
useEffect(() => {
|
||||
setEmployeeFilter(employees?.filter((emp) => emp.email != null) || []);
|
||||
}, [employees]);
|
||||
|
||||
// Initialize checked employees based on assignedEmployee prop
|
||||
useEffect(() => {
|
||||
if (Array.isArray(assignedEmployee)) {
|
||||
const initialStatus = assignedEmployee.map((id) => ({
|
||||
employeeId: id,
|
||||
isActive: true,
|
||||
}));
|
||||
setEmployeeStatusList(initialStatus);
|
||||
}
|
||||
}, [assignedEmployee]);
|
||||
|
||||
// Send updated list to parent
|
||||
useEffect(() => {
|
||||
if (onChange) {
|
||||
onChange(employeeStatusList);
|
||||
}
|
||||
}, [employeeStatusList]);
|
||||
|
||||
const handleCheckboxChange = (id) => {
|
||||
setSelectedIds((prev) =>
|
||||
prev.includes(id) ? prev?.filter((empId) => empId !== id) : [...prev, id]
|
||||
);
|
||||
setEmployeeStatusList((prev) => {
|
||||
const exists = prev.find((emp) => emp.employeeId === id);
|
||||
if (exists) {
|
||||
return prev.map((emp) =>
|
||||
emp.employeeId === id ? { ...emp, isActive: !emp.isActive } : emp
|
||||
);
|
||||
} else {
|
||||
return [...prev, { employeeId: id, isActive: true }];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const getSelectedEmployees = () => {
|
||||
console.log("Selected Employee IDs:", selectedIds);
|
||||
const isChecked = (id) => {
|
||||
const found = employeeStatusList.find((emp) => emp.employeeId === id);
|
||||
return found?.isActive || false;
|
||||
};
|
||||
|
||||
// Sorting
|
||||
const {
|
||||
items: sortedEmployees,
|
||||
requestSort,
|
||||
sortConfig,
|
||||
} = useSortableData(employees, {
|
||||
} = useSortableData(employeefiltered, {
|
||||
key: (e) => `${e?.firstName} ${e?.lastName}`,
|
||||
direction: "asc",
|
||||
});
|
||||
@ -34,21 +66,13 @@ const EmployeeList = ({ employees }) => {
|
||||
};
|
||||
|
||||
const filteredEmployees = sortedEmployees?.filter((employee) => {
|
||||
const fullName =
|
||||
`${employee?.firstName} ${employee?.lastName}`?.toLowerCase();
|
||||
// const email = employee.email.toLowerCase();
|
||||
// const role = employee.jobRole.toLowerCase();
|
||||
const term = searchTerm?.toLowerCase();
|
||||
|
||||
return fullName.includes(term);
|
||||
// email.includes(term) ||
|
||||
// role.includes(term)
|
||||
const fullName = `${employee?.firstName} ${employee?.lastName}`?.toLowerCase();
|
||||
return fullName.includes(searchTerm.toLowerCase());
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="d-flex justify-content-between mt-2">
|
||||
<p className="m-0 fs-6 fw-normal">Add Employee</p>
|
||||
<div className="d-flex justify-content-between align-items-center mt-2">
|
||||
<p className="m-0 fw-normal">Add Employee</p>
|
||||
<div className="px-1">
|
||||
<input
|
||||
type="search"
|
||||
@ -72,27 +96,25 @@ const EmployeeList = ({ employees }) => {
|
||||
>
|
||||
<span className="ps-2">Name {getSortIcon()}</span>
|
||||
</th>
|
||||
<th className="text-start">Role</th>
|
||||
<th scope="col">Status</th>
|
||||
<th className="text-start">Bucket</th>
|
||||
<th className="text-start">Email</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{employees.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan={4} >
|
||||
<div className="d-flex justify-content-center align-items-center py-5">
|
||||
No Employee Available
|
||||
</div>
|
||||
<td colSpan={4}>
|
||||
<div className="d-flex justify-content-center align-items-center py-5">
|
||||
No Employee Available
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
) : filteredEmployees.length === 0 ? (
|
||||
<tr className="my-4">
|
||||
<td colSpan={4}>
|
||||
<div className="d-flex justify-content-center align-items-center py-5">
|
||||
No Matchinng Employee Found.
|
||||
</div>
|
||||
<td colSpan={4}>
|
||||
<div className="d-flex justify-content-center align-items-center py-5">
|
||||
No Matching Employee Found.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
@ -103,36 +125,18 @@ const EmployeeList = ({ employees }) => {
|
||||
<input
|
||||
className="form-check-input me-3 mt-1"
|
||||
type="checkbox"
|
||||
checked={selectedIds.includes(employee.id)}
|
||||
checked={isChecked(employee.id)}
|
||||
onChange={() => handleCheckboxChange(employee.id)}
|
||||
/>
|
||||
<div>
|
||||
<p className="fw-semibold mb-0">
|
||||
<p className="fw-normal mb-0">
|
||||
{`${employee.firstName} ${employee.lastName}`}
|
||||
</p>
|
||||
<small className="text-muted">{employee.email}</small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="text-start">
|
||||
<small className="text-muted">{employee.jobRole}</small>
|
||||
</td>
|
||||
<td>
|
||||
<span
|
||||
className={`badge rounded-pill px-3 py-1 ${
|
||||
employee.isActive
|
||||
? "bg-success-subtle text-success"
|
||||
: "bg-danger-subtle text-danger"
|
||||
}`}
|
||||
>
|
||||
{employee.isActive ? "Active" : "Inactive"}
|
||||
</span>
|
||||
</td>
|
||||
<td className="text-start">
|
||||
<small className="text-muted">
|
||||
<i className="fa fa-hashtag" aria-hidden="true"></i>{" "}
|
||||
{employee.jobRole}
|
||||
</small>
|
||||
<small className="text-muted">{employee.email}</small>
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
|
@ -16,7 +16,8 @@ import ConfirmModal from "../common/ConfirmModal";
|
||||
const ManageBucket = () => {
|
||||
const [bucketList, setBucketList] = useState([]);
|
||||
const { employeesList } = useAllEmployees(false);
|
||||
const { buckets, loading,refetch } = useBuckets();
|
||||
const [selectedEmployee, setSelectEmployee] = useState([]);
|
||||
const { buckets, loading, refetch } = useBuckets();
|
||||
const [action_bucket, setAction_bucket] = useState(false);
|
||||
const [isSubmitting, setSubmitting] = useState(false);
|
||||
const [selected_bucket, select_bucket] = useState(null);
|
||||
@ -54,28 +55,89 @@ const ManageBucket = () => {
|
||||
|
||||
const onSubmit = async (data) => {
|
||||
setSubmitting(true);
|
||||
|
||||
try {
|
||||
const cache_buckets = getCachedData("buckets") || [];
|
||||
let response;
|
||||
|
||||
// Utility: Compare arrays regardless of order
|
||||
const arraysAreEqual = (a, b) => {
|
||||
if (a.length !== b.length) return false;
|
||||
const setA = new Set(a);
|
||||
const setB = new Set(b);
|
||||
return [...setA].every((id) => setB.has(id));
|
||||
};
|
||||
|
||||
// UPDATE existing bucket
|
||||
if (selected_bucket) {
|
||||
let payload = { ...data, id: selected_bucket.id };
|
||||
const payload = { ...data, id: selected_bucket.id };
|
||||
|
||||
// 1. Update bucket details
|
||||
response = await DirectoryRepository.UpdateBuckets(
|
||||
selected_bucket.id,
|
||||
payload
|
||||
);
|
||||
const cache_buckets = getCachedData("buckets") || [];
|
||||
|
||||
const updatedBuckets = cache_buckets.map((bucket) =>
|
||||
bucket.id === selected_bucket.id ? response?.data : bucket
|
||||
);
|
||||
|
||||
cacheData("buckets", updatedBuckets);
|
||||
setBucketList(updatedBuckets);
|
||||
|
||||
// 2. Update employee assignments if they changed
|
||||
const existingEmployeeIds = selected_bucket?.employeeIds || [];
|
||||
const employeesToUpdate = selectedEmployee.filter((emp) => {
|
||||
const isExisting = existingEmployeeIds.includes(emp.employeeId);
|
||||
return (!isExisting && emp.isActive) || (isExisting && !emp.isActive);
|
||||
});
|
||||
|
||||
// Create a filtered list of active employee IDs to compare
|
||||
const newActiveEmployeeIds = selectedEmployee
|
||||
.filter((emp) => {
|
||||
const isExisting = existingEmployeeIds.includes(emp.employeeId);
|
||||
return (
|
||||
(!isExisting && emp.isActive) || (isExisting && !emp.isActive)
|
||||
);
|
||||
})
|
||||
.map((emp) => emp.employeeId);
|
||||
|
||||
if (
|
||||
!arraysAreEqual(newActiveEmployeeIds, existingEmployeeIds) &&
|
||||
employeesToUpdate.length != 0
|
||||
) {
|
||||
try {
|
||||
response = await DirectoryRepository.AssignedBuckets(
|
||||
selected_bucket.id,
|
||||
employeesToUpdate
|
||||
);
|
||||
} catch (assignError) {
|
||||
const assignMessage =
|
||||
assignError?.response?.data?.message ||
|
||||
assignError?.message ||
|
||||
"Error assigning employees.";
|
||||
showToast(assignMessage, "error");
|
||||
}
|
||||
}
|
||||
const updatedData = cache_buckets?.map((bucket) =>
|
||||
bucket.id === response?.data?.id ? response.data : bucket
|
||||
);
|
||||
|
||||
cacheData( "buckets", updatedData );
|
||||
|
||||
setBucketList(updatedData)
|
||||
showToast("Bucket Updated Successfully", "success");
|
||||
} else {
|
||||
}
|
||||
|
||||
// CREATE new bucket
|
||||
else {
|
||||
response = await DirectoryRepository.CreateBuckets(data);
|
||||
const cache_buckets = getCachedData("buckets") || [];
|
||||
|
||||
const updatedBuckets = [...cache_buckets, response?.data];
|
||||
cacheData("buckets", updatedBuckets);
|
||||
setBucketList(updatedBuckets);
|
||||
setBucketList( updatedBuckets );
|
||||
|
||||
|
||||
showToast("Bucket Created Successfully", "success");
|
||||
}
|
||||
|
||||
@ -86,18 +148,20 @@ const ManageBucket = () => {
|
||||
error?.message ||
|
||||
"Error occurred during API call";
|
||||
showToast(message, "error");
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteContact = async () => {
|
||||
try {
|
||||
const resp = await DirectoryRepository.DeleteBucket( deleteBucket );
|
||||
const cache_buckets = getCachedData("buckets") || [];
|
||||
const updatedBuckets = cache_buckets.filter((bucket) =>
|
||||
bucket.id != deleteBucket
|
||||
);
|
||||
cacheData("buckets", updatedBuckets);
|
||||
setBucketList(updatedBuckets);
|
||||
const resp = await DirectoryRepository.DeleteBucket(deleteBucket);
|
||||
const cache_buckets = getCachedData("buckets") || [];
|
||||
const updatedBuckets = cache_buckets.filter(
|
||||
(bucket) => bucket.id != deleteBucket
|
||||
);
|
||||
cacheData("buckets", updatedBuckets);
|
||||
setBucketList(updatedBuckets);
|
||||
showToast("Bucket deleted successfully", "success");
|
||||
setDeleteBucket(null);
|
||||
} catch (error) {
|
||||
@ -131,7 +195,6 @@ const ManageBucket = () => {
|
||||
const name = bucket.name?.toLowerCase();
|
||||
return name?.includes(term);
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{deleteBucket && (
|
||||
@ -173,13 +236,14 @@ const ManageBucket = () => {
|
||||
placeholder="Search Bucket ..."
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
/>
|
||||
<i
|
||||
className={`bx bx-refresh cursor-pointer fs-4 ${loading ? "spin" : ""
|
||||
}`}
|
||||
title="Refresh"
|
||||
onClick={() => rrefetch()}
|
||||
/>
|
||||
/>
|
||||
<i
|
||||
className={`bx bx-refresh cursor-pointer fs-4 ${
|
||||
loading ? "spin" : ""
|
||||
}`}
|
||||
title="Refresh"
|
||||
onClick={() => refetch()}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -251,36 +315,37 @@ const ManageBucket = () => {
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
{sortedBucktesList.map((bucket) => (
|
||||
<tr key={bucket.id}>
|
||||
<td colSpan={2} className="text-start text-wrap">
|
||||
<i className="bx bx-right-arrow-alt me-1"></i>{" "}
|
||||
{bucket.name}
|
||||
</td>
|
||||
<td
|
||||
className="text-start d-none d-sm-table-cell text-wrap"
|
||||
style={{ width: "60%" }}
|
||||
>
|
||||
{bucket.description}
|
||||
</td>
|
||||
<td className="justify-content-center">
|
||||
<div className="d-flex justify-content-center align-items-center gap-2">
|
||||
<i
|
||||
className="bx bx-edit bx-sm text-primary cursor-pointer"
|
||||
onClick={() => {
|
||||
select_bucket(bucket);
|
||||
setAction_bucket(true);
|
||||
}}
|
||||
></i>
|
||||
<i
|
||||
className="bx bx-trash bx-sm text-danger cursor-pointer"
|
||||
onClick={() => setDeleteBucket(bucket?.id)}
|
||||
></i>
|
||||
<i className="bx bx-user-plus cursor-pointer"></i>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
{!loading &&
|
||||
sortedBucktesList.map((bucket) => (
|
||||
<tr key={bucket.id}>
|
||||
<td colSpan={2} className="text-start text-wrap">
|
||||
<i className="bx bx-right-arrow-alt me-1"></i>{" "}
|
||||
{bucket.name}
|
||||
</td>
|
||||
<td
|
||||
className="text-start d-none d-sm-table-cell text-wrap"
|
||||
style={{ width: "60%" }}
|
||||
>
|
||||
{bucket.description}
|
||||
</td>
|
||||
<td className="justify-content-center">
|
||||
<div className="d-flex justify-content-center align-items-center gap-2">
|
||||
<i
|
||||
className="bx bx-edit bx-sm text-primary cursor-pointer"
|
||||
onClick={() => {
|
||||
select_bucket(bucket);
|
||||
setAction_bucket(true);
|
||||
}}
|
||||
></i>
|
||||
<i
|
||||
className="bx bx-trash bx-sm text-danger cursor-pointer"
|
||||
onClick={() => setDeleteBucket(bucket?.id)}
|
||||
></i>
|
||||
<i className="bx bx-user-plus cursor-pointer"></i>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@ -310,9 +375,18 @@ const ManageBucket = () => {
|
||||
</small>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{selected_bucket && (
|
||||
<EmployeeList
|
||||
employees={employeesList}
|
||||
onChange={(data) => setSelectEmployee(data)}
|
||||
assignedEmployee={selected_bucket?.employeeIds}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="mt-2 d-flex justify-content-center gap-3">
|
||||
<button
|
||||
type="reset"
|
||||
onClick={()=>handleBack()}
|
||||
className="btn btn-sm btn-secondary"
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
@ -327,8 +401,6 @@ const ManageBucket = () => {
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<EmployeeList employees={employeesList} />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user