diff --git a/frontend/src/stores/attendanceStore.js b/frontend/src/stores/attendanceStore.js index f69b8b4..069ddf1 100644 --- a/frontend/src/stores/attendanceStore.js +++ b/frontend/src/stores/attendanceStore.js @@ -54,15 +54,25 @@ export const useAttendanceStore = defineStore('attendanceStore', () => { for (let d = 1; d <= daysInMonth.value; d++) { const dateStr = `${year.value}-${month.value.toString().padStart(2, '0')}-${d.toString().padStart(2, '0')}` - const dayData = response.days.find((day) => day.check_in.startsWith(dateStr)) || {} + const dayEntries = response.days.filter((day) => day.check_in && day.check_in.startsWith(dateStr)) + + // Sort entries by check-in time to ensure correct order + dayEntries.sort((a, b) => new Date(a.check_in) - new Date(b.check_in)) + + const entryTimes = dayEntries.map((entry) => utils.extractTimeFromDateString(entry.check_in)) + const exitTimes = dayEntries.map((entry) => utils.extractTimeFromDateString(entry.check_out)) + const attendance_reason_ids = dayEntries.flatMap( + (entry) => entry.attendance_reason_ids || [], + ) + const isPublicHoliday = response.public_holidays.some((h) => h.date === dateStr) - const alert = dayData.attendance_reason_ids?.length > 0 + const alert = attendance_reason_ids.length > 0 const day = { dayOfMonth: d, dayOfWeek: utils.getDayOfWeek(dateStr), - entryTime: utils.extractTimeFromDateString(dayData.check_in), - exitTime: utils.extractTimeFromDateString(dayData.check_out), + entryTime: entryTimes, + exitTime: exitTimes, isSickLeave: false, isHolidayLeave: false, isPublicHoliday: isPublicHoliday, diff --git a/frontend/src/utils/utils.js b/frontend/src/utils/utils.js index c8f5a7f..ea547c4 100644 --- a/frontend/src/utils/utils.js +++ b/frontend/src/utils/utils.js @@ -95,21 +95,34 @@ function isValidWorkDay(day) { return day.dayOfWeek !== 'So' && day.dayOfWeek !== 'Nd' && !day.isPublicHoliday } -function calculateWorkedTime(entryTime, exitTime) { - if (!entryTime || !exitTime || typeof entryTime !== 'string' || typeof exitTime !== 'string') { - return 0 - } - const [eh, em] = entryTime.split(':').map(Number) - const [xh, xm] = exitTime.split(':').map(Number) - - if ([eh, em, xh, xm].some((v) => typeof v !== 'number' || isNaN(v))) { +function calculateWorkedTime(entryTimes, exitTimes) { + if (!entryTimes || !exitTimes || !Array.isArray(entryTimes) || !Array.isArray(exitTimes) || entryTimes.length === 0) { return 0 } - const start = eh * 60 + em - const end = xh * 60 + xm + let totalWorkedMinutes = 0 + for (let i = 0; i < entryTimes.length; i++) { + const entryTime = entryTimes[i] + // Use the corresponding exit time, or skip if it doesn't exist + const exitTime = exitTimes[i] - let worked = (end - start) / 60 + if (!entryTime || !exitTime || typeof entryTime !== 'string' || typeof exitTime !== 'string') { + continue + } + + const [eh, em] = entryTime.split(':').map(Number) + const [xh, xm] = exitTime.split(':').map(Number) + + if ([eh, em, xh, xm].some((v) => typeof v !== 'number' || isNaN(v))) { + continue + } + + const start = eh * 60 + em + const end = xh * 60 + xm + totalWorkedMinutes += end - start + } + + const worked = totalWorkedMinutes / 60 return parseFloat(worked.toFixed(9)) } @@ -130,23 +143,30 @@ function floatHoursToHHMM(decimalHours) { } function calculateDay(day) { - let exitTime = day.exitTime + // Create a mutable copy of exit times to potentially add the current time. + const exitTimes = [...day.exitTime] - if (!day.exitTime || typeof day.exitTime !== 'string' || day.exitTime.trim() === '') { - // const now = new Date().toLocaleString('pl-PL', { timeZone: 'Europe/Warsaw' }) + // If there's one more entry than exits, it means the user is currently clocked in. + if (day.entryTime.length > 0 && day.entryTime.length === day.exitTime.length + 1) { const now = new Date() const hh = String(now.getHours()).padStart(2, '0') const mm = String(now.getMinutes()).padStart(2, '0') const ss = String(now.getSeconds()).padStart(2, '0') - exitTime = `${hh}:${mm}:${ss}` + // Add the current time as the "exit" for the last entry. + exitTimes.push(`${hh}:${mm}:${ss}`) } - if (!day.entryTime || typeof day.entryTime !== 'string' || day.entryTime.trim() === '') { + if (day.entryTime.length === 0) { day.workedHours = 0 } else { - day.workedHours = calculateWorkedTime(day.entryTime, exitTime) - 0.25 - day.workedHours = parseFloat(day.workedHours.toFixed(9)) - day.exitTime = exitTime + // The -0.25 for a 15-minute break seems to be a business rule. + // It should probably only be subtracted once per day, not per interval. + // Let's subtract it from the total. + let totalHours = calculateWorkedTime(day.entryTime, exitTimes) + if (totalHours > 0) { + totalHours -= 0.25 + } + day.workedHours = parseFloat(totalHours.toFixed(9)) } if (isValidWorkDay(day) && !day.isHolidayLeave && !day.isSickLeave) {