fixed check ehcke issue
This commit is contained in:
parent
166b0a1caf
commit
0d1d51d56b
@ -127,3 +127,11 @@
|
|||||||
.fs-md-xlarge { font-size: 170% !important; }
|
.fs-md-xlarge { font-size: 170% !important; }
|
||||||
.fs-md-xxlarge { font-size: calc(1.725rem + 5.7vw) !important; }
|
.fs-md-xxlarge { font-size: calc(1.725rem + 5.7vw) !important; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Tables */
|
||||||
|
.table th.actions-col,
|
||||||
|
.table td.actions-col {
|
||||||
|
width: 1%;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|||||||
@ -12,8 +12,17 @@ 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";
|
||||||
import Pagination from "../common/Pagination";
|
import Pagination from "../common/Pagination";
|
||||||
|
import { SpinnerLoader } from "../common/Loader";
|
||||||
|
|
||||||
const Attendance = ({ getRole, handleModalData, searchTerm, projectId, organizationId, includeInactive, date }) => {
|
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();
|
||||||
@ -24,12 +33,12 @@ const Attendance = ({ getRole, handleModalData, searchTerm, projectId, organizat
|
|||||||
attendance,
|
attendance,
|
||||||
loading: attLoading,
|
loading: attLoading,
|
||||||
recall: attrecall,
|
recall: attrecall,
|
||||||
isFetching
|
isFetching,
|
||||||
} = useAttendance(selectedProject, organizationId, includeInactive, date);
|
} = 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
|
||||||
)
|
)
|
||||||
: attendance;
|
: attendance;
|
||||||
|
|
||||||
const attendanceList = Array.isArray(filteredAttendance)
|
const attendanceList = Array.isArray(filteredAttendance)
|
||||||
@ -71,19 +80,19 @@ const Attendance = ({ getRole, handleModalData, searchTerm, projectId, organizat
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Reset pagination when the filter or search term changes
|
// Reset pagination when the filter or search term changes
|
||||||
useEffect(() => {
|
useEffect(() => {}, [finalFilteredData]);
|
||||||
}, [finalFilteredData]);
|
|
||||||
|
|
||||||
|
|
||||||
const handler = useCallback(
|
const handler = useCallback(
|
||||||
(msg) => {
|
(msg) => {
|
||||||
if (selectedProject == msg.projectId) {
|
if (selectedProject == msg.projectId) {
|
||||||
queryClient.setQueryData(["attendance", selectedProject], (oldData) => {
|
queryClient.setQueryData(["attendance", selectedProject], (oldData) => {
|
||||||
if (!oldData) {
|
if (!oldData) {
|
||||||
queryClient.invalidateQueries({ queryKey: ["attendance"] })
|
queryClient.invalidateQueries({ queryKey: ["attendance"] });
|
||||||
};
|
}
|
||||||
return oldData.map((record) =>
|
return oldData.map((record) =>
|
||||||
record.employeeId === msg.response.employeeId ? { ...record, ...msg.response } : record
|
record.employeeId === msg.response.employeeId
|
||||||
|
? { ...record, ...msg.response }
|
||||||
|
: record
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -109,16 +118,11 @@ const Attendance = ({ getRole, handleModalData, searchTerm, projectId, organizat
|
|||||||
return () => eventBus.off("employee", employeeHandler);
|
return () => eventBus.off("employee", employeeHandler);
|
||||||
}, [employeeHandler]);
|
}, [employeeHandler]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div className="table-responsive text-nowrap ">
|
||||||
className="table-responsive text-nowrap h-100"
|
<div className="d-flex justify-content-between align-items-center py-2">
|
||||||
style={{ minHeight: "200px" }} // Ensures fixed height
|
|
||||||
>
|
|
||||||
<div className="d-flex text-start align-items-center py-2">
|
|
||||||
<strong>Date : {formatUTCToLocalTime(todayDate)}</strong>
|
<strong>Date : {formatUTCToLocalTime(todayDate)}</strong>
|
||||||
<div className="form-check form-switch text-start m-0 ms-5">
|
<div className="form-check form-switch text-start m-0 ms-5">
|
||||||
<input
|
<input
|
||||||
@ -134,23 +138,29 @@ const Attendance = ({ getRole, handleModalData, searchTerm, projectId, organizat
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{attLoading ? (
|
{attLoading ? (
|
||||||
<div>Loading...</div>
|
<div
|
||||||
|
className="d-flex justify-content-center align-items-center"
|
||||||
|
style={{ minHeight: "70vh" }}
|
||||||
|
>
|
||||||
|
<SpinnerLoader />
|
||||||
|
</div>
|
||||||
) : currentItems?.length > 0 ? (
|
) : currentItems?.length > 0 ? (
|
||||||
<>
|
<>
|
||||||
<table className="table ">
|
<table className="table table-hover ">
|
||||||
<thead>
|
<thead>
|
||||||
<tr className="border-top-1">
|
<tr className="border-top-1">
|
||||||
<th colSpan={2}>Name</th>
|
<th colSpan={2}>Name</th>
|
||||||
<th>Role</th>
|
<th className="text-start actions-col text-center">Role</th>
|
||||||
{/* <th>Organization</th> */}
|
{/* <th>Organization</th> */}
|
||||||
<th>
|
<th>
|
||||||
<i className="bx bxs-down-arrow-alt text-success"></i>
|
<i className="bx bxs-down-arrow-alt text-success"></i>
|
||||||
Check-In
|
Check-In
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
<i className="bx bxs-up-arrow-alt text-danger"></i>Check-Out
|
<i className="bx bxs-up-arrow-alt text-danger"></i>
|
||||||
|
Check-Out
|
||||||
</th>
|
</th>
|
||||||
<th>Actions</th>
|
<th className="actions-col">Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="table-border-bottom-0 ">
|
<tbody className="table-border-bottom-0 ">
|
||||||
@ -190,7 +200,7 @@ const Attendance = ({ getRole, handleModalData, searchTerm, projectId, organizat
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>{item.jobRoleName}</td>
|
<td className="text-start action-col">{item.jobRoleName}</td>
|
||||||
{/* <td>{item.organizationName || "--"}</td> */}
|
{/* <td>{item.organizationName || "--"}</td> */}
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
@ -204,7 +214,7 @@ const Attendance = ({ getRole, handleModalData, searchTerm, projectId, organizat
|
|||||||
: "--"}
|
: "--"}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td className="text-center">
|
<td className="text-center actions-col">
|
||||||
<RenderAttendanceStatus
|
<RenderAttendanceStatus
|
||||||
attendanceData={item}
|
attendanceData={item}
|
||||||
handleModalData={handleModalData}
|
handleModalData={handleModalData}
|
||||||
@ -236,8 +246,8 @@ const Attendance = ({ getRole, handleModalData, searchTerm, projectId, organizat
|
|||||||
{searchTerm
|
{searchTerm
|
||||||
? "No results found for your search."
|
? "No results found for your search."
|
||||||
: attendanceList.length === 0
|
: attendanceList.length === 0
|
||||||
? "No employees assigned to the project."
|
? "No employees assigned to the project."
|
||||||
: "No pending records available."}
|
: "No pending records available."}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -5,7 +5,11 @@ import { convertShortTime, formatUTCToLocalTime } from "../../utils/dateUtils";
|
|||||||
import RenderAttendanceStatus from "./RenderAttendanceStatus";
|
import RenderAttendanceStatus from "./RenderAttendanceStatus";
|
||||||
import { useSelector, useDispatch } from "react-redux";
|
import { useSelector, useDispatch } from "react-redux";
|
||||||
import DateRangePicker from "../common/DateRangePicker";
|
import DateRangePicker from "../common/DateRangePicker";
|
||||||
import { clearCacheKey, getCachedData, useSelectedProject } from "../../slices/apiDataManager";
|
import {
|
||||||
|
clearCacheKey,
|
||||||
|
getCachedData,
|
||||||
|
useSelectedProject,
|
||||||
|
} from "../../slices/apiDataManager";
|
||||||
import eventBus from "../../services/eventBus";
|
import eventBus from "../../services/eventBus";
|
||||||
import AttendanceRepository from "../../repositories/AttendanceRepository";
|
import AttendanceRepository from "../../repositories/AttendanceRepository";
|
||||||
import { useAttendancesLogs } from "../../hooks/useAttendance";
|
import { useAttendancesLogs } from "../../hooks/useAttendance";
|
||||||
@ -13,6 +17,7 @@ import { queryClient } from "../../layouts/AuthLayout";
|
|||||||
import { ITEMS_PER_PAGE } from "../../utils/constants";
|
import { ITEMS_PER_PAGE } from "../../utils/constants";
|
||||||
import Pagination from "../common/Pagination";
|
import Pagination from "../common/Pagination";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { SpinnerLoader } from "../common/Loader";
|
||||||
|
|
||||||
const usePagination = (data, itemsPerPage) => {
|
const usePagination = (data, itemsPerPage) => {
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
@ -36,14 +41,11 @@ const usePagination = (data, itemsPerPage) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const AttendanceLog = ({ handleModalData, searchTerm, organizationId }) => {
|
const AttendanceLog = ({ handleModalData, searchTerm, organizationId }) => {
|
||||||
// const selectedProject = useSelector(
|
|
||||||
// (store) => store.localVariables.projectId
|
|
||||||
// );
|
|
||||||
const selectedProject = useSelectedProject();
|
const selectedProject = useSelectedProject();
|
||||||
const [dateRange, setDateRange] = useState({ startDate: "", endDate: "" });
|
const [dateRange, setDateRange] = useState({ startDate: "", endDate: "" });
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [showPending, setShowPending] = useState(false)
|
const [showPending, setShowPending] = useState(false);
|
||||||
|
|
||||||
const [isRefreshing, setIsRefreshing] = useState(false);
|
const [isRefreshing, setIsRefreshing] = useState(false);
|
||||||
const [processedData, setProcessedData] = useState([]);
|
const [processedData, setProcessedData] = useState([]);
|
||||||
@ -87,57 +89,65 @@ const AttendanceLog = ({ handleModalData, searchTerm, organizationId }) => {
|
|||||||
dateRange.endDate,
|
dateRange.endDate,
|
||||||
organizationId
|
organizationId
|
||||||
);
|
);
|
||||||
const filtering = useCallback((dataToFilter) => {
|
const filtering = useCallback(
|
||||||
const filteredData = showPending
|
(dataToFilter) => {
|
||||||
? dataToFilter.filter((item) => item.checkOutTime === null)
|
const filteredData = showPending
|
||||||
: dataToFilter;
|
? dataToFilter.filter((item) => item.checkOutTime === null)
|
||||||
|
: dataToFilter;
|
||||||
|
|
||||||
const group1 = filteredData
|
const group1 = filteredData
|
||||||
.filter((d) => d.activity === 1 && isSameDay(d.checkInTime))
|
.filter((d) => d.activity === 1 && isSameDay(d.checkInTime))
|
||||||
.sort(sortByName);
|
.sort(sortByName);
|
||||||
const group2 = filteredData
|
const group2 = filteredData
|
||||||
.filter((d) => d.activity === 4 && isSameDay(d.checkOutTime))
|
.filter((d) => d.activity === 4 && isSameDay(d.checkOutTime))
|
||||||
.sort(sortByName);
|
.sort(sortByName);
|
||||||
const group3 = filteredData
|
const group3 = filteredData
|
||||||
.filter((d) => d.activity === 1 && isBeforeToday(d.checkInTime))
|
.filter((d) => d.activity === 1 && isBeforeToday(d.checkInTime))
|
||||||
.sort(sortByName);
|
.sort(sortByName);
|
||||||
const group4 = filteredData.filter(
|
const group4 = filteredData.filter(
|
||||||
(d) => d.activity === 4 && isBeforeToday(d.checkOutTime)
|
(d) => d.activity === 4 && isBeforeToday(d.checkOutTime)
|
||||||
);
|
);
|
||||||
const group5 = filteredData
|
const group5 = filteredData
|
||||||
.filter((d) => d.activity === 2 && isBeforeToday(d.checkOutTime))
|
.filter((d) => d.activity === 2 && isBeforeToday(d.checkOutTime))
|
||||||
.sort(sortByName);
|
.sort(sortByName);
|
||||||
const group6 = filteredData
|
const group6 = filteredData
|
||||||
.filter((d) => d.activity === 5)
|
.filter((d) => d.activity === 5)
|
||||||
.sort(sortByName);
|
.sort(sortByName);
|
||||||
|
|
||||||
const sortedList = [...group1, ...group2, ...group3, ...group4, ...group5, ...group6];
|
const sortedList = [
|
||||||
|
...group1,
|
||||||
|
...group2,
|
||||||
|
...group3,
|
||||||
|
...group4,
|
||||||
|
...group5,
|
||||||
|
...group6,
|
||||||
|
];
|
||||||
|
|
||||||
// Group by date
|
// Group by date
|
||||||
const groupedByDate = sortedList.reduce((acc, item) => {
|
const groupedByDate = sortedList.reduce((acc, item) => {
|
||||||
const date = (item.checkInTime || item.checkOutTime)?.split("T")[0];
|
const date = (item.checkInTime || item.checkOutTime)?.split("T")[0];
|
||||||
if (date) {
|
if (date) {
|
||||||
acc[date] = acc[date] || [];
|
acc[date] = acc[date] || [];
|
||||||
acc[date].push(item);
|
acc[date].push(item);
|
||||||
}
|
}
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
const sortedDates = Object.keys(groupedByDate).sort(
|
const sortedDates = Object.keys(groupedByDate).sort(
|
||||||
(a, b) => new Date(b) - new Date(a)
|
(a, b) => new Date(b) - new Date(a)
|
||||||
);
|
);
|
||||||
|
|
||||||
const finalData = sortedDates.flatMap((date) => groupedByDate[date]);
|
const finalData = sortedDates.flatMap((date) => groupedByDate[date]);
|
||||||
setProcessedData(finalData);
|
setProcessedData(finalData);
|
||||||
}, [showPending]);
|
},
|
||||||
|
[showPending]
|
||||||
|
);
|
||||||
useEffect(() => {
|
|
||||||
if (data?.length) {
|
|
||||||
filtering(data);
|
|
||||||
}
|
|
||||||
}, [data, showPending]);
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (data?.length) {
|
||||||
|
filtering(data);
|
||||||
|
}
|
||||||
|
}, [data, showPending]);
|
||||||
|
|
||||||
// New useEffect to handle search filtering
|
// New useEffect to handle search filtering
|
||||||
const filteredSearchData = useMemo(() => {
|
const filteredSearchData = useMemo(() => {
|
||||||
@ -151,8 +161,6 @@ const AttendanceLog = ({ handleModalData, searchTerm, organizationId }) => {
|
|||||||
});
|
});
|
||||||
}, [processedData, searchTerm]);
|
}, [processedData, searchTerm]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
currentPage,
|
currentPage,
|
||||||
totalPages,
|
totalPages,
|
||||||
@ -210,7 +218,7 @@ const AttendanceLog = ({ handleModalData, searchTerm, organizationId }) => {
|
|||||||
// })
|
// })
|
||||||
// );
|
// );
|
||||||
|
|
||||||
refetch()
|
refetch();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[selectedProject, dateRange, data, refetch]
|
[selectedProject, dateRange, data, refetch]
|
||||||
@ -221,29 +229,29 @@ const AttendanceLog = ({ handleModalData, searchTerm, organizationId }) => {
|
|||||||
return () => eventBus.off("employee", employeeHandler);
|
return () => eventBus.off("employee", employeeHandler);
|
||||||
}, [employeeHandler]);
|
}, [employeeHandler]);
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
className="dataTables_length text-start py-2 d-flex justify-content-between"
|
className="dataTables_length text-start py-2 d-flex justify-content-between "
|
||||||
id="DataTables_Table_0_length"
|
id="DataTables_Table_0_length"
|
||||||
>
|
>
|
||||||
<div className=" col-12">
|
<div className=" col-12">
|
||||||
<DateRangePicker
|
<DateRangePicker
|
||||||
onRangeChange={setDateRange}
|
onRangeChange={setDateRange}
|
||||||
defaultStartDate={yesterday}
|
defaultStartDate={yesterday}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className="table-responsive text-nowrap " >
|
<div className="table-responsive text-nowrap ">
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<div className="d-flex justify-content-center align-items-center">
|
<div
|
||||||
<p className="text-secondary">Loading...</p>
|
className="d-flex justify-content-center align-items-center"
|
||||||
|
style={{ minHeight: "70vh" }}
|
||||||
|
>
|
||||||
|
<SpinnerLoader/>
|
||||||
</div>
|
</div>
|
||||||
) : filteredSearchData?.length > 0 ? (
|
) : filteredSearchData?.length > 0 ? (
|
||||||
<table className="table mb-0">
|
<table className="table mb-0 table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th className="border-top-1" colSpan={2}>
|
<th className="border-top-1" colSpan={2}>
|
||||||
@ -253,12 +261,13 @@ const AttendanceLog = ({ handleModalData, searchTerm, organizationId }) => {
|
|||||||
{/* <th>Organization</th> */}
|
{/* <th>Organization</th> */}
|
||||||
|
|
||||||
<th>
|
<th>
|
||||||
<i className="bx bxs-down-arrow-alt text-success"></i> Check-In
|
<i className="bx bxs-down-arrow-alt text-success"></i>{" "}
|
||||||
|
Check-In
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
<i className="bx bxs-up-arrow-alt text-danger"></i> Check-Out
|
<i className="bx bxs-up-arrow-alt text-danger"></i> Check-Out
|
||||||
</th>
|
</th>
|
||||||
<th>Action</th>
|
<th className="actions-col">Action</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -269,9 +278,9 @@ const AttendanceLog = ({ handleModalData, searchTerm, organizationId }) => {
|
|||||||
const previousAttendance = arr[index - 1];
|
const previousAttendance = arr[index - 1];
|
||||||
const previousDate = previousAttendance
|
const previousDate = previousAttendance
|
||||||
? moment(
|
? moment(
|
||||||
previousAttendance.checkInTime ||
|
previousAttendance.checkInTime ||
|
||||||
previousAttendance.checkOutTime
|
previousAttendance.checkOutTime
|
||||||
).format("YYYY-MM-DD")
|
).format("YYYY-MM-DD")
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
if (!previousDate || currentDate !== previousDate) {
|
if (!previousDate || currentDate !== previousDate) {
|
||||||
@ -281,8 +290,8 @@ const AttendanceLog = ({ handleModalData, searchTerm, organizationId }) => {
|
|||||||
className="table-row-header"
|
className="table-row-header"
|
||||||
>
|
>
|
||||||
<td colSpan={8} className="text-start">
|
<td colSpan={8} className="text-start">
|
||||||
<strong className="mx-2">
|
<strong className="d-inline-block my-1 ms-2">
|
||||||
{formatUTCToLocalTime(currentDate)}
|
{formatUTCToLocalTime(currentDate)}
|
||||||
</strong>
|
</strong>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -299,7 +308,9 @@ const AttendanceLog = ({ handleModalData, searchTerm, organizationId }) => {
|
|||||||
<div className="d-flex flex-column">
|
<div className="d-flex flex-column">
|
||||||
<a
|
<a
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
navigate(`/employee/${attendance.employeeId}?for=attendance`)
|
navigate(
|
||||||
|
`/employee/${attendance.employeeId}?for=attendance`
|
||||||
|
)
|
||||||
}
|
}
|
||||||
className="text-heading text-truncate cursor-pointer"
|
className="text-heading text-truncate cursor-pointer"
|
||||||
>
|
>
|
||||||
@ -322,7 +333,7 @@ const AttendanceLog = ({ handleModalData, searchTerm, organizationId }) => {
|
|||||||
? convertShortTime(attendance.checkOutTime)
|
? convertShortTime(attendance.checkOutTime)
|
||||||
: "--"}
|
: "--"}
|
||||||
</td>
|
</td>
|
||||||
<td className="text-center">
|
<td className="text-center actions-col">
|
||||||
<RenderAttendanceStatus
|
<RenderAttendanceStatus
|
||||||
attendanceData={attendance}
|
attendanceData={attendance}
|
||||||
handleModalData={handleModalData}
|
handleModalData={handleModalData}
|
||||||
@ -337,7 +348,14 @@ const AttendanceLog = ({ handleModalData, searchTerm, organizationId }) => {
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
) : (
|
) : (
|
||||||
<div className="my-12"><span className="text-secondary">No data for this date range. Please choose another.</span></div>
|
<div
|
||||||
|
className="d-flex justify-content-center align-items-center"
|
||||||
|
style={{ minHeight: "70vh" }}
|
||||||
|
>
|
||||||
|
<p className="text-secondary mb-0">
|
||||||
|
No data for this date range. Please choose another.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{paginatedAttendances?.length == 0 && filteredSearchData?.length > 0 && (
|
{paginatedAttendances?.length == 0 && filteredSearchData?.length > 0 && (
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import { useQueryClient } from "@tanstack/react-query";
|
|||||||
import Pagination from "../common/Pagination";
|
import Pagination from "../common/Pagination";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { employee } from "../../data/masters";
|
import { employee } from "../../data/masters";
|
||||||
|
import { SpinnerLoader } from "../common/Loader";
|
||||||
|
|
||||||
const Regularization = ({ handleRequest, searchTerm, projectId, organizationId, IncludeInActive }) => {
|
const Regularization = ({ handleRequest, searchTerm, projectId, organizationId, IncludeInActive }) => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
@ -135,11 +136,14 @@ const Regularization = ({ handleRequest, searchTerm, projectId, organizationId,
|
|||||||
<div>
|
<div>
|
||||||
<div className="table-responsive text-nowrap pb-4" style={{ minHeight: "200px" }}>
|
<div className="table-responsive text-nowrap pb-4" style={{ minHeight: "200px" }}>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="d-flex justify-content-center align-items-center" style={{ height: "200px" }}>
|
<div
|
||||||
<p className="text-secondary">Loading...</p>
|
className="d-flex justify-content-center align-items-center"
|
||||||
|
style={{ minHeight: "70vh" }}
|
||||||
|
>
|
||||||
|
<SpinnerLoader/>
|
||||||
</div>
|
</div>
|
||||||
) : currentItems?.length > 0 ? (
|
) : currentItems?.length > 0 ? (
|
||||||
<table className="table mb-0">
|
<table className="table mb-0 table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th colSpan={2}>Name</th>
|
<th colSpan={2}>Name</th>
|
||||||
@ -154,7 +158,7 @@ const Regularization = ({ handleRequest, searchTerm, projectId, organizationId,
|
|||||||
|
|
||||||
<th>Request By</th>
|
<th>Request By</th>
|
||||||
<th>Requested At</th>
|
<th>Requested At</th>
|
||||||
<th>Action</th>
|
<th className="actions-col">Action</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|||||||
@ -19,6 +19,13 @@ import { useProjectName } from "../../hooks/useProjects";
|
|||||||
import ExpenseAnalysis from "./ExpenseAnalysis";
|
import ExpenseAnalysis from "./ExpenseAnalysis";
|
||||||
import ExpenseStatus from "./ExpenseStatus";
|
import ExpenseStatus from "./ExpenseStatus";
|
||||||
import ExpenseByProject from "./ExpenseByProject";
|
import ExpenseByProject from "./ExpenseByProject";
|
||||||
|
import { useHasUserPermission } from "../../hooks/useHasUserPermission";
|
||||||
|
import {
|
||||||
|
APPROVE_EXPENSE,
|
||||||
|
EXPENSE_MANAGE,
|
||||||
|
VIEW_ALL_EXPNESE,
|
||||||
|
} from "../../utils/constants";
|
||||||
|
import { useHasAnyPermission } from "../../hooks/useExpense";
|
||||||
|
|
||||||
const Dashboard = () => {
|
const Dashboard = () => {
|
||||||
// const { projectsCardData } = useDashboardProjectsCardData();
|
// const { projectsCardData } = useDashboardProjectsCardData();
|
||||||
@ -29,34 +36,40 @@ const Dashboard = () => {
|
|||||||
const projectId = useSelector((store) => store.localVariables.projectId);
|
const projectId = useSelector((store) => store.localVariables.projectId);
|
||||||
const isAllProjectsSelected = projectId === null;
|
const isAllProjectsSelected = projectId === null;
|
||||||
|
|
||||||
|
const isViewExpense = useHasAnyPermission(
|
||||||
|
VIEW_ALL_EXPNESE,
|
||||||
|
APPROVE_EXPENSE,
|
||||||
|
EXPENSE_MANAGE
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<div className="container-fluid py-5">
|
<div className="container-fluid py-5">
|
||||||
<div className="row mb-6 g-6">
|
{isViewExpense && (
|
||||||
<div className="col-12 col-xl-8">
|
<div className="row mb-6 g-6">
|
||||||
<div className="card h-100">
|
<div className="col-12 col-xl-8">
|
||||||
<ExpenseAnalysis />
|
<div className="card h-100">
|
||||||
|
<ExpenseAnalysis />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="col-12 col-xl-4 col-md-6">
|
||||||
|
<div className="card h-100">
|
||||||
|
<ExpenseStatus />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="row vh-100">
|
||||||
|
{!isAllProjectsSelected && (
|
||||||
|
<div className="col-12 col-md-6 mb-sm-0 mb-4 ">
|
||||||
|
<AttendanceOverview />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="col-12 col-md-6">
|
||||||
|
<ExpenseByProject />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="col-12 col-xl-4 col-md-6">
|
|
||||||
<div className="card h-100">
|
|
||||||
<ExpenseStatus />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="row vh-100">
|
|
||||||
{!isAllProjectsSelected && (
|
|
||||||
<div className="col-12 col-md-6 mb-sm-0 mb-4 ">
|
|
||||||
<AttendanceOverview />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="col-12 col-md-6">
|
|
||||||
<ExpenseByProject />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -19,3 +19,14 @@ const Loader = () => {
|
|||||||
|
|
||||||
export default Loader;
|
export default Loader;
|
||||||
|
|
||||||
|
|
||||||
|
export const SpinnerLoader = ()=>{
|
||||||
|
return (
|
||||||
|
<div className="text-center">
|
||||||
|
<div className="spinner-border text-primary mb-3" role="status">
|
||||||
|
<span className="visually-hidden">Loading...</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-secondary mb-0">Loading attendance data...</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -169,7 +169,7 @@ const AttendancePage = () => {
|
|||||||
</div>
|
</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 pb-2 mt-md-0 ms-md-auto d-flex gap-2 align-items-center nav-tabs">
|
||||||
{/* Organization Dropdown */}
|
{/* Organization Dropdown */}
|
||||||
{/* <select
|
{/* <select
|
||||||
className="form-select form-select-sm"
|
className="form-select form-select-sm"
|
||||||
@ -206,7 +206,7 @@ const AttendancePage = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="tab-content attedanceTabs py-0 px-1 px-sm-3 pb-10">
|
<div className="tab-content attedanceTabs py-0 px-1 px-sm-3 pb-10 page-min-h">
|
||||||
|
|
||||||
<>
|
<>
|
||||||
{activeTab === "all" && (
|
{activeTab === "all" && (
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user