Merge branch 'Ashutosh_Enhancement#132_Int_To_Guid' of https://git.marcoaiot.com/admin/marco.pms.web into Ashutosh_Enhancement#132_Int_To_Guid
This commit is contained in:
commit
cd2e563e1d
@ -1,4 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useState,useEffect } from "react";
|
||||
import moment from "moment";
|
||||
import Avatar from "../common/Avatar";
|
||||
import { convertShortTime } from "../../utils/dateUtils";
|
||||
@ -7,17 +7,37 @@ import usePagination from "../../hooks/usePagination";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
const Attendance = ({ attendance, getRole, handleModalData }) => {
|
||||
const { currentPage, totalPages, currentItems, paginate } = usePagination(
|
||||
attendance,
|
||||
5
|
||||
);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
|
||||
// Ensure attendance is an array
|
||||
const attendanceList = Array.isArray(attendance) ? attendance : [];
|
||||
|
||||
// Function to sort by first and last name
|
||||
const sortByName = (a, b) => {
|
||||
const nameA = (a.firstName + a.lastName).toLowerCase();
|
||||
const nameB = (b.firstName + b.lastName).toLowerCase();
|
||||
return nameA.localeCompare(nameB);
|
||||
};
|
||||
|
||||
// Filter employees based on activity
|
||||
const group1 = attendanceList
|
||||
.filter((d) => d.activity === 1 || d.activity === 4)
|
||||
.sort(sortByName);
|
||||
const group2 = attendanceList
|
||||
.filter((d) => d.activity === 0)
|
||||
.sort(sortByName);
|
||||
|
||||
const filteredData = [...group1, ...group2];
|
||||
|
||||
const { currentPage, totalPages, currentItems, paginate } = usePagination(
|
||||
filteredData,
|
||||
5
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<div className="table-responsive text-nowrap">
|
||||
{attendance && attendance.length > 0 ? (
|
||||
{attendance && attendance.length > 0 && (
|
||||
<>
|
||||
<table className="table ">
|
||||
<thead>
|
||||
@ -96,6 +116,9 @@ const Attendance = ({ attendance, getRole, handleModalData }) => {
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
{!attendance && (
|
||||
<span>No employees assigned to the project</span>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@ -145,8 +168,6 @@ const Attendance = ({ attendance, getRole, handleModalData }) => {
|
||||
</nav>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<span>No employees assigned to the project</span>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
|
@ -16,9 +16,41 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
|
||||
const dispatch = useDispatch();
|
||||
const { data, loading, error } = useSelector((store) => store.attendanceLogs);
|
||||
const [isRefreshing, setIsRefreshing] = useState(true);
|
||||
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0); // Strip time to compare dates only
|
||||
|
||||
const isSameDay = (dateStr) => {
|
||||
if (!dateStr) return false;
|
||||
const d = new Date(dateStr);
|
||||
d.setHours(0, 0, 0, 0);
|
||||
return d.getTime() === today.getTime();
|
||||
};
|
||||
|
||||
const isBeforeToday = (dateStr) => {
|
||||
if (!dateStr) return false;
|
||||
const d = new Date(dateStr);
|
||||
d.setHours(0, 0, 0, 0);
|
||||
return d.getTime() < today.getTime();
|
||||
};
|
||||
|
||||
const sortByName = (a, b) => {
|
||||
const nameA = a.firstName.toLowerCase() + a.lastName.toLowerCase();
|
||||
const nameB = b.firstName.toLowerCase() + b.lastName.toLowerCase();
|
||||
return nameA.localeCompare(nameB);
|
||||
};
|
||||
|
||||
const group1 = data.filter(d => d.activity === 1 && isSameDay(d.checkInTime)).sort(sortByName);
|
||||
const group2 = data.filter(d => d.activity === 4 && isSameDay(d.checkOutTime)).sort(sortByName);
|
||||
const group3 = data.filter(d => d.activity === 1 && isBeforeToday(d.checkInTime)).sort(sortByName);
|
||||
const group4 = data.filter(d => d.activity === 4 && isBeforeToday(d.checkOutTime)).sort(sortByName);
|
||||
const group5 = data.filter(d => d.activity === 5).sort(sortByName);
|
||||
|
||||
const sortedFinalList = [...group1, ...group2, ...group3, ...group4, ...group5];
|
||||
|
||||
const currentDate = new Date().toLocaleDateString( "en-CA" );
|
||||
const { currentPage, totalPages, currentItems, paginate } = usePagination(
|
||||
data,
|
||||
sortedFinalList,
|
||||
5
|
||||
);
|
||||
|
||||
@ -35,7 +67,6 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
|
||||
}
|
||||
}, [dateRange, projectId, isRefreshing]);
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
|
@ -73,7 +73,7 @@ const CheckCheckOutmodel = ({modeldata,closeModal,handleSubmitForm,}) => {
|
||||
label="Choose a time"
|
||||
onChange={(e) => setValue("markTime", e)}
|
||||
interval={10}
|
||||
activity={modeldata?.action}
|
||||
checkOutTime={modeldata?.checkOutTime}
|
||||
checkInTime={modeldata?.checkInTime}
|
||||
/>
|
||||
{errors. markTime && <p className="text-danger">{errors.markTime.message}</p>}
|
||||
|
@ -5,6 +5,7 @@ import RegularizationActions from "./RegularizationActions";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useRegularizationRequests } from "../../hooks/useAttendance";
|
||||
import moment from "moment";
|
||||
import usePagination from "../../hooks/usePagination";
|
||||
|
||||
const Regularization = ({ handleRequest }) => {
|
||||
var selectedProject = useSelector((store) => store.localVariables.projectId);
|
||||
@ -16,6 +17,19 @@ const Regularization = ({ handleRequest }) => {
|
||||
setregularizedList(regularizes);
|
||||
}, [regularizes]);
|
||||
|
||||
const sortByName = (a, b) => {
|
||||
const nameA = a.firstName.toLowerCase() + a.lastName.toLowerCase();
|
||||
const nameB = b.firstName.toLowerCase() + b.lastName.toLowerCase();
|
||||
return nameA.localeCompare(nameB);
|
||||
};
|
||||
|
||||
const filteredData = regularizesList.sort(sortByName)
|
||||
|
||||
const { currentPage, totalPages, currentItems, paginate } = usePagination(
|
||||
filteredData,
|
||||
5
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="table-responsive text-nowrap">
|
||||
<table className="table mb-0">
|
||||
@ -79,6 +93,51 @@ const Regularization = ({ handleRequest }) => {
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
{!loading && (
|
||||
<nav aria-label="Page ">
|
||||
<ul className="pagination pagination-sm justify-content-end py-1">
|
||||
<li
|
||||
className={`page-item ${
|
||||
currentPage === 1 ? "disabled" : ""
|
||||
}`}
|
||||
>
|
||||
<button
|
||||
className="page-link btn-xs"
|
||||
onClick={() => paginate(currentPage - 1)}
|
||||
>
|
||||
«
|
||||
</button>
|
||||
</li>
|
||||
{[...Array(totalPages)].map((_, index) => (
|
||||
<li
|
||||
key={index}
|
||||
className={`page-item ${
|
||||
currentPage === index + 1 ? "active" : ""
|
||||
}`}
|
||||
>
|
||||
<button
|
||||
className="page-link "
|
||||
onClick={() => paginate(index + 1)}
|
||||
>
|
||||
{index + 1}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
<li
|
||||
className={`page-item ${
|
||||
currentPage === totalPages ? "disabled" : ""
|
||||
}`}
|
||||
>
|
||||
<button
|
||||
className="page-link "
|
||||
onClick={() => paginate(currentPage + 1)}
|
||||
>
|
||||
»
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -18,7 +18,8 @@ const RenderAttendanceStatus = ({ attendanceData, handleModalData,Tab,currentDat
|
||||
employeeId: attendanceData?.employeeId,
|
||||
id: attendanceData?.id,
|
||||
currentDate,
|
||||
checkInTime:attendanceData.checkInTime
|
||||
checkInTime: attendanceData.checkInTime,
|
||||
checkOutTime:attendanceData.checkOutTime
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, { useState, useRef, useEffect } from "react";
|
||||
import {THRESH_HOLD} from "../../utils/constants"
|
||||
|
||||
const TimePicker = ({ label, onChange, interval = 10, value,checkInTime,activity }) => {
|
||||
const TimePicker = ({ label, onChange, interval = 10, value,checkInTime,checkOutTime }) => {
|
||||
const [time, setTime] = useState(value || "");
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const dropdownRef = useRef(null);
|
||||
@ -41,59 +42,51 @@ const TimePicker = ({ label, onChange, interval = 10, value,checkInTime,activity
|
||||
|
||||
const checkInDate = checkInTime ? new Date(checkInTime) : null;
|
||||
|
||||
|
||||
const fullStart = checkInDate ? new Date(checkInDate) : new Date();
|
||||
fullStart.setHours(0, 0, 0, 0);
|
||||
|
||||
const fullEnd = checkInDate ? new Date(checkInDate) : new Date();
|
||||
fullEnd.setHours(23, 59, 59, 999);
|
||||
|
||||
const checkOutDate = checkOutTime ? new Date(checkOutTime) : null;
|
||||
|
||||
const dayStart = new Date();
|
||||
const dayEnd = new Date();
|
||||
if (checkInDate) {
|
||||
dayStart.setTime(checkInDate.getTime());
|
||||
dayEnd.setTime(checkInDate.getTime());
|
||||
}
|
||||
dayStart.setHours(0, 0, 0, 0);
|
||||
dayEnd.setHours(23, 59, 59, 999);
|
||||
|
||||
let minSelectable = null;
|
||||
let maxSelectable = null;
|
||||
|
||||
// Activity 0: Time slots based on current time
|
||||
if (activity === 0 && !checkInDate) {
|
||||
minSelectable = new Date(currentSlot.getTime() - 60 * 60000); // one hour before current time
|
||||
if (!checkInDate) {
|
||||
// Case 1: No check-in time (new check-in)
|
||||
minSelectable = new Date(dayStart);
|
||||
maxSelectable = new Date(currentSlot);
|
||||
}
|
||||
// Activity 1: Time slots based on check-in time today
|
||||
else if (activity === 1 && checkInDate) {
|
||||
if (checkInDate.toDateString() === now.toDateString()) {
|
||||
else if (checkInDate && !checkOutDate) {
|
||||
const hoursDiff = (now - checkInDate) / (1000 * 60 * 60);
|
||||
if (hoursDiff < THRESH_HOLD) {
|
||||
// Case 2: Check-in present, no checkout, within THRESH_HOLD hours
|
||||
minSelectable = new Date(checkInDate);
|
||||
maxSelectable = new Date(currentSlot);
|
||||
} else {
|
||||
// Case 4: Check-in present, no checkout, more than THRESH_HOLD hours
|
||||
minSelectable = new Date(checkInDate);
|
||||
maxSelectable = new Date(dayEnd);
|
||||
}
|
||||
}
|
||||
// Activity 2: Time slots from check-in time to 12:00 AM of the same day
|
||||
else if (activity === 2 && checkInDate) {
|
||||
// Set minSelectable to the exact check-in time
|
||||
minSelectable = new Date(checkInDate);
|
||||
|
||||
// Set maxSelectable to midnight (12:00 AM) of the same day
|
||||
maxSelectable = new Date(checkInDate);
|
||||
maxSelectable.setHours(23, 59, 59, 999); // Set to 23:59:59.999 (end of the day)
|
||||
} else if (checkInDate && checkOutDate) {
|
||||
// Case 3: Both check-in and checkout present
|
||||
const isSameDay = new Date(checkOutDate).toDateString() === new Date().toDateString();
|
||||
minSelectable = new Date(checkOutDate);
|
||||
maxSelectable = isSameDay ? new Date(dayEnd) : new Date(currentSlot);
|
||||
}
|
||||
|
||||
// Loop through every slot in the day to check which ones are selectable
|
||||
const slot = new Date(fullStart.getTime());
|
||||
while (slot <= fullEnd) {
|
||||
const slot = new Date(dayStart.getTime());
|
||||
while (slot <= dayEnd) {
|
||||
const formatted = formatTime(slot);
|
||||
let isSelectable = false;
|
||||
|
||||
// For activity 2, allow only slots from the check-in time up to 12:00 AM of the same day
|
||||
if (minSelectable && maxSelectable) {
|
||||
if (activity === 2 && checkInDate) {
|
||||
// Ensure slot is greater than or equal to minSelectable and less than or equal to maxSelectable
|
||||
isSelectable = slot >= minSelectable && slot <= maxSelectable;
|
||||
} else {
|
||||
isSelectable = slot >= minSelectable && slot <= maxSelectable;
|
||||
}
|
||||
}
|
||||
|
||||
slots.push({
|
||||
time: formatted,
|
||||
isSelectable,
|
||||
});
|
||||
const isSelectable = slot >= minSelectable && slot <= maxSelectable;
|
||||
slots.push({ time: formatted, isSelectable });
|
||||
|
||||
slot.setMinutes(slot.getMinutes() + interval);
|
||||
}
|
||||
@ -137,13 +130,6 @@ const TimePicker = ({ label, onChange, interval = 10, value,checkInTime,activity
|
||||
}
|
||||
}, [isOpen, time]);
|
||||
|
||||
useEffect(() => {
|
||||
if (activity === 2 && checkInTime) {
|
||||
const slots = generateTimeSlots();
|
||||
const selectableSlots = slots.filter(slot => slot.isSelectable);
|
||||
console.log("Selectable Slots for Activity 2:", selectableSlots);
|
||||
}
|
||||
}, [activity, checkInTime]);
|
||||
|
||||
return (
|
||||
<div className="position-relative w-100" ref={dropdownRef}>
|
||||
@ -205,4 +191,4 @@ const TimePicker = ({ label, onChange, interval = 10, value,checkInTime,activity
|
||||
);
|
||||
};
|
||||
|
||||
export default TimePicker;
|
||||
export default TimePicker;
|
@ -74,15 +74,31 @@ const useAttendanceStatus = (attendanceData) => {
|
||||
text: "Regularize",
|
||||
color: 'btn-warning',
|
||||
});
|
||||
}else if(activity === 4 && checkInTime !== null && checkOutTime !== null && !timeElapsed(checkInTime,THRESH_HOLD) ){
|
||||
setStatus({
|
||||
status: "Check-In",
|
||||
action: ACTIONS.CHECK_IN,
|
||||
disabled: false,
|
||||
text: "Check In",
|
||||
color: 'btn-primary',
|
||||
})
|
||||
}else if(activity === 2 && checkInTime !== null ){
|
||||
} else if ( activity === 4 && checkInTime !== null && checkOutTime !== null && !timeElapsed( checkInTime, THRESH_HOLD ) )
|
||||
{
|
||||
|
||||
if ( activity === 4 && checkInTime !== null && checkOutTime !== null && new Date(checkOutTime).toDateString() !== new Date().toDateString())
|
||||
{
|
||||
setStatus( {
|
||||
status: "Approved",
|
||||
action: ACTIONS.APPROVED,
|
||||
disabled: true,
|
||||
text: "Approved",
|
||||
color: 'btn-success',
|
||||
} );
|
||||
} else
|
||||
{
|
||||
setStatus( {
|
||||
status: "Check-In",
|
||||
action: ACTIONS.CHECK_IN,
|
||||
disabled: false,
|
||||
text: "Check In",
|
||||
color: 'btn-primary',
|
||||
} )
|
||||
}
|
||||
}
|
||||
else if ( activity === 2 && checkInTime !== null )
|
||||
{
|
||||
setStatus({
|
||||
status: "Requested",
|
||||
action: ACTIONS.REQUESTED,
|
||||
|
Loading…
x
Reference in New Issue
Block a user