Merge pull request 'Calling api for Attendance component for Organization.' (#420) from Kartik_Task_Att#1236 into Organization_Management

Reviewed-on: #420
This commit is contained in:
Vikas Nale 2025-09-22 04:07:09 +00:00
commit 693cabf63d
6 changed files with 155 additions and 109 deletions

View File

@ -12,22 +12,19 @@ import { useQueryClient } from "@tanstack/react-query";
import eventBus from "../../services/eventBus"; import eventBus from "../../services/eventBus";
import { useSelectedProject } from "../../slices/apiDataManager"; import { useSelectedProject } from "../../slices/apiDataManager";
const Attendance = ({ getRole, handleModalData, searchTerm }) => { const Attendance = ({ getRole, handleModalData, searchTerm, projectId, organizationId, includeInactive, date }) => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const navigate = useNavigate(); const navigate = useNavigate();
const [todayDate, setTodayDate] = useState(new Date()); const [todayDate, setTodayDate] = useState(new Date());
const [ShowPending, setShowPending] = useState(false); const [ShowPending, setShowPending] = useState(false);
// const selectedProject = useSelector(
// (store) => store.localVariables.projectId
// );
const selectedProject = useSelectedProject(); const selectedProject = useSelectedProject();
const { const {
attendance, attendance,
loading: attLoading, loading: attLoading,
recall: attrecall, recall: attrecall,
isFetching isFetching
} = useAttendance(selectedProject); } = useAttendance(selectedProject, organizationId, includeInactive, date);
const filteredAttendance = ShowPending const filteredAttendance = ShowPending
? attendance?.filter( ? attendance?.filter(
(att) => att?.checkInTime !== null && att?.checkOutTime === null (att) => att?.checkInTime !== null && att?.checkOutTime === null
@ -67,43 +64,6 @@ const Attendance = ({ getRole, handleModalData, searchTerm }) => {
}); });
}, [group1, group2, searchTerm]); }, [group1, group2, searchTerm]);
// const finalFilteredData = useMemo(() => {
// const combinedData = [...group1, ...group2];
// let tempData = combinedData;
// // Search filter
// if (searchTerm) {
// const lowercasedSearchTerm = searchTerm.toLowerCase();
// tempData = tempData.filter((item) => {
// const fullName = `${item.firstName} ${item.lastName}`.toLowerCase();
// const role = item.jobRoleName?.toLowerCase() || "";
// return (
// fullName.includes(lowercasedSearchTerm) ||
// role.includes(lowercasedSearchTerm) // also search by role
// );
// });
// }
// // Organization filter
// if (filters?.selectedOrganization) {
// tempData = tempData.filter(
// (item) => item.organization?.name === filters.selectedOrganization
// );
// }
// // Services filter
// if (filters?.selectedServices?.length > 0) {
// tempData = tempData.filter((item) =>
// filters.selectedServices.includes(item.service?.name)
// );
// }
// return tempData;
// }, [group1, group2, searchTerm, filters]);
const { currentPage, totalPages, currentItems, paginate } = usePagination( const { currentPage, totalPages, currentItems, paginate } = usePagination(
finalFilteredData, finalFilteredData,
ITEMS_PER_PAGE ITEMS_PER_PAGE

View File

@ -33,7 +33,7 @@ const usePagination = (data, itemsPerPage) => {
}; };
}; };
const AttendanceLog = ({ handleModalData, searchTerm }) => { const AttendanceLog = ({ handleModalData, searchTerm ,organizationId}) => {
// const selectedProject = useSelector( // const selectedProject = useSelector(
// (store) => store.localVariables.projectId // (store) => store.localVariables.projectId
// ); // );
@ -81,7 +81,8 @@ const AttendanceLog = ({ handleModalData, searchTerm }) => {
} = useAttendancesLogs( } = useAttendancesLogs(
selectedProject, selectedProject,
dateRange.startDate, dateRange.startDate,
dateRange.endDate dateRange.endDate,
organizationId
); );
const filtering = (data) => { const filtering = (data) => {
const filteredData = showPending const filteredData = showPending

View File

@ -10,13 +10,13 @@ import eventBus from "../../services/eventBus";
import { cacheData, clearCacheKey, useSelectedProject } from "../../slices/apiDataManager"; import { cacheData, clearCacheKey, useSelectedProject } from "../../slices/apiDataManager";
import { useQueryClient } from "@tanstack/react-query"; import { useQueryClient } from "@tanstack/react-query";
const Regularization = ({ handleRequest, searchTerm }) => { const Regularization = ({ handleRequest, searchTerm,projectId, organizationId, IncludeInActive }) => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
// var selectedProject = useSelector((store) => store.localVariables.projectId); // var selectedProject = useSelector((store) => store.localVariables.projectId);
const selectedProject = useSelectedProject(); const selectedProject = useSelectedProject();
const [regularizesList, setregularizedList] = useState([]); const [regularizesList, setregularizedList] = useState([]);
const { regularizes, loading, error, refetch } = const { regularizes, loading, error, refetch } =
useRegularizationRequests(selectedProject); useRegularizationRequests(selectedProject, organizationId, IncludeInActive);
useEffect(() => { useEffect(() => {
setregularizedList(regularizes); setregularizedList(regularizes);

View File

@ -12,46 +12,76 @@ import { setDefaultDateRange } from "../slices/localVariablesSlice";
// ----------------------------Query----------------------------- // ----------------------------Query-----------------------------
export const useAttendance = (projectId) => { // export const useAttendance = (projectId) => {
const dispatch = useDispatch() // const dispatch = useDispatch()
// const {
// data: attendance = [],
// isLoading: loading,
// error,
// refetch: recall,
// isFetching
// } = useQuery({
// queryKey: ["attendance", projectId],
// queryFn: async () => {
// const response = await AttendanceRepository.getAttendance(projectId);
// return response.data;
// },
// enabled: !!projectId,
// onError: (error) => {
// showToast(error.message || "Error while fetching Attendance", "error");
// },
// });
// return {
// attendance,
// loading,
// error,
// recall,
// isFetching
// };
// };
export const useAttendance = (projectId, organizationId, includeInactive = false, date = null) => {
const dispatch = useDispatch();
const { const {
data: attendance = [], data: attendance = [],
isLoading: loading, isLoading: loading,
error, error,
refetch: recall, refetch: recall,
isFetching isFetching,
} = useQuery({ } = useQuery({
queryKey: ["attendance", projectId], queryKey: ["attendance", projectId, organizationId, includeInactive, date], // include filters in cache key
queryFn: async () => { queryFn: async () => {
const response = await AttendanceRepository.getAttendance(projectId); const response = await AttendanceRepository.getAttendance(
projectId,
organizationId,
includeInactive,
date
);
return response.data; return response.data;
}, },
enabled: !!projectId, enabled: !!projectId, // only run if projectId exists
onError: (error) => { onError: (error) => {
showToast(error.message || "Error while fetching Attendance", "error"); showToast(error.message || "Error while fetching Attendance", "error");
}, },
}); });
return { return { attendance, loading, error, recall, isFetching };
attendance,
loading,
error,
recall,
isFetching
};
}; };
export const useAttendancesLogs = (projectId, fromDate, toDate) => { export const useAttendancesLogs = (projectId, fromDate, toDate,organizationId) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const enabled = !!projectId && !!fromDate && !!toDate; const enabled = !!projectId && !!fromDate && !!toDate;
const query = useQuery({ const query = useQuery({
queryKey: ['attendanceLogs', projectId, fromDate, toDate], queryKey: ['attendanceLogs', projectId, fromDate, toDate,organizationId],
queryFn: async () => { queryFn: async () => {
const res = await AttendanceRepository.getAttendanceFilteredByDate( const res = await AttendanceRepository.getAttendanceFilteredByDate(
projectId, projectId,
fromDate, fromDate,
toDate toDate,
organizationId
); );
return res.data; return res.data;
}, },
@ -112,30 +142,58 @@ export const useAttendanceByEmployee = (employeeId, fromDate, toDate) => {
}); });
}; };
export const useRegularizationRequests = (projectId) => { // export const useRegularizationRequests = (projectId) => {
// const {
// data: regularizes = [],
// isLoading: loading,
// error,
// refetch,
// } = useQuery({
// queryKey: ["regularizedList", projectId],
// queryFn: async () => {
// const response = await AttendanceRepository.getRegularizeList(projectId);
// return response.data;
// },
// enabled: !!projectId,
// onError: (error) => {
// showToast(error.message || "Error while fetching Regularization Requests", "error");
// },
// });
// return {
// regularizes,
// loading,
// error,
// refetch,
// };
// };
export const useRegularizationRequests = (projectId, organizationId, IncludeInActive = false) => {
const dispatch = useDispatch();
const { const {
data: regularizes = [], data: regularizes = [],
isLoading: loading, isLoading: loading,
error, error,
refetch, refetch: recall,
isFetching,
} = useQuery({ } = useQuery({
queryKey: ["regularizedList", projectId], queryKey: ["regularizedList", projectId, organizationId, IncludeInActive], // include filters in cache key
queryFn: async () => { queryFn: async () => {
const response = await AttendanceRepository.getRegularizeList(projectId); const response = await AttendanceRepository.getRegularizeList(
projectId,
organizationId,
IncludeInActive,
);
return response.data; return response.data;
}, },
enabled: !!projectId, enabled: !!projectId, // only run if projectId exists
onError: (error) => { onError: (error) => {
showToast(error.message || "Error while fetching Regularization Requests", "error"); showToast(error.message || "Error while fetching regularizes", "error");
}, },
}); });
return { return { regularizes, loading, error, recall, isFetching };
regularizes,
loading,
error,
refetch,
};
}; };

View File

@ -16,7 +16,7 @@ import { setProjectId } from "../../slices/localVariablesSlice";
import { useHasUserPermission } from "../../hooks/useHasUserPermission"; import { useHasUserPermission } from "../../hooks/useHasUserPermission";
import { REGULARIZE_ATTENDANCE } from "../../utils/constants"; import { REGULARIZE_ATTENDANCE } from "../../utils/constants";
import eventBus from "../../services/eventBus"; import eventBus from "../../services/eventBus";
import { useProjectName } from "../../hooks/useProjects"; import { useProjectAssignedOrganizations, useProjectName } from "../../hooks/useProjects";
import GlobalModel from "../../components/common/GlobalModel"; import GlobalModel from "../../components/common/GlobalModel";
import CheckCheckOutmodel from "../../components/Activities/CheckCheckOutForm"; import CheckCheckOutmodel from "../../components/Activities/CheckCheckOutForm";
import AttendLogs from "../../components/Activities/AttendLogs"; import AttendLogs from "../../components/Activities/AttendLogs";
@ -43,6 +43,9 @@ const AttendancePage = () => {
selectedServices: [], selectedServices: [],
}); });
const { data: organizations = [], isLoading: orgLoading } =
useProjectAssignedOrganizations(selectedProject);
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
markTime: "", markTime: "",
description: "", description: "",
@ -168,37 +171,30 @@ const AttendancePage = () => {
</ul> </ul>
</div> </div>
{/* Single search input that moves */}
{/* <div className="col-12 col-md-auto mt-2 mt-md-0 ms-md-auto d-flex gap-2 align-items-center">
<input
type="text"
className="form-control form-control-sm"
placeholder="Search Employee..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
style={{ minWidth: "200px" }}
/>
</div> */}
{/* Search + Organization filter */} {/* Search + Organization filter */}
<div className="col-12 col-md-auto mt-2 mt-md-0 ms-md-auto d-flex gap-2 align-items-center"> <div className="col-12 col-md-auto mt-2 mt-md-0 ms-md-auto d-flex gap-2 align-items-center">
{/* Organization Dropdown */} {/* Organization Dropdown */}
<select {organizations?.length > 1 && (
className="form-select form-select-sm" <select
style={{ minWidth: "180px" }} className="form-select form-select-sm"
value={appliedFilters.selectedOrganization} style={{ minWidth: "180px" }}
onChange={(e) => value={appliedFilters.selectedOrganization}
setAppliedFilters((prev) => ({ onChange={(e) =>
...prev, setAppliedFilters((prev) => ({
selectedOrganization: e.target.value, ...prev,
})) selectedOrganization: e.target.value,
} }))
> }
<option value="">All Organizations</option> disabled={orgLoading}
<option value="Org A">Org A</option> >
<option value="Org B">Org B</option> <option value="">All Organizations</option>
<option value="Org C">Org C</option> {organizations?.map((org) => (
</select> <option key={org.id} value={org.id}>
{org.name}
</option>
))}
</select>
)}
{/* Search Input */} {/* Search Input */}
<input <input
@ -223,6 +219,7 @@ const AttendancePage = () => {
handleModalData={handleModalData} handleModalData={handleModalData}
getRole={getRole} getRole={getRole}
searchTerm={searchTerm} searchTerm={searchTerm}
organizationId={appliedFilters.selectedOrganization}
/> />
</div> </div>
)} )}
@ -231,6 +228,7 @@ const AttendancePage = () => {
<AttendanceLog <AttendanceLog
handleModalData={handleModalData} handleModalData={handleModalData}
searchTerm={searchTerm} searchTerm={searchTerm}
organizationId={appliedFilters.selectedOrganization}
/> />
</div> </div>
)} )}
@ -238,6 +236,7 @@ const AttendancePage = () => {
<div className="tab-pane fade show active py-0"> <div className="tab-pane fade show active py-0">
<Regularization <Regularization
searchTerm={searchTerm} searchTerm={searchTerm}
organizationId={appliedFilters.selectedOrganization}
/> />
</div> </div>
)} )}

View File

@ -2,8 +2,22 @@ import { api } from "../utils/axiosClient";
const AttendanceRepository = { const AttendanceRepository = {
markAttendance: (data) => api.post("/api/attendance/record", data), markAttendance: (data) => api.post("/api/attendance/record", data),
getAttendance: (id) => api.get(`api/attendance/project/team?projectId=${id}`),
getAttendanceFilteredByDate: (projectId, fromDate, toDate) => { getAttendance: (projectId, organizationId, includeInactive,date) => {
let url = `/api/attendance/project/team?projectId=${projectId}`;
const params = [];
if (organizationId) params.push(`organizationId=${organizationId}`);
if (includeInactive) params.push(`includeInactive=${includeInactive}`);
if (date) params.push(`date=${date}`);
if (params.length > 0) {
url += `&${params.join("&")}`; }
return api.get(url);
},
getAttendanceFilteredByDate: (projectId, fromDate, toDate,organizationId) => {
let url = `api/Attendance/project/log?projectId=${projectId}`; let url = `api/Attendance/project/log?projectId=${projectId}`;
if (fromDate) { if (fromDate) {
url += `&dateFrom=${fromDate}`; url += `&dateFrom=${fromDate}`;
@ -12,12 +26,26 @@ const AttendanceRepository = {
if (toDate) { if (toDate) {
url += `&dateTo=${toDate}`; url += `&dateTo=${toDate}`;
} }
if (organizationId) {
url += `&organizationId=${organizationId}`;
}
return api.get(url); return api.get(url);
}, },
getAttendanceLogs: (id) => api.get(`api/attendance/log/attendance/${id}`), getAttendanceLogs: (id) => api.get(`api/attendance/log/attendance/${id}`),
getRegularizeList: (id) =>
api.get(`api/attendance/regularize?projectId=${id}`), getRegularizeList: (projectId, organizationId, IncludeInActive) => {
let url = `/api/attendance/regularize?projectId=${projectId}`;
const params = [];
if (organizationId) params.push(`organizationId=${organizationId}`);
if (IncludeInActive) params.push(`IncludeInActive=${IncludeInActive}`);
if (params.length > 0) {
url += `&${params.join("&")}`; }
return api.get(url);
},
getAttendanceByEmployee: (employeeId, fromDate, toDate) => { getAttendanceByEmployee: (employeeId, fromDate, toDate) => {
let url = `api/Attendance/log/employee/${employeeId}?`; let url = `api/Attendance/log/employee/${employeeId}?`;