fix: improve holiday name retrieval by comparing year, month, and day directly to avoid timezone issues

refactor: change exported variables to local scope in state management for better encapsulation
This commit is contained in:
Felix Schlusche
2025-10-23 19:36:55 +02:00
parent 426859ea0d
commit af23aa369c
3 changed files with 63 additions and 64 deletions

View File

@@ -129,11 +129,16 @@ function getPublicHolidays(year, bundesland) {
*/ */
function getHolidayName(date) { function getHolidayName(date) {
const year = date.getFullYear(); const year = date.getFullYear();
const month = date.getMonth();
const day = date.getDate();
const holidays = getPublicHolidays(year, currentBundesland); const holidays = getPublicHolidays(year, currentBundesland);
const dateStr = date.toISOString().split('T')[0]; // Compare year, month, and day directly (avoid timezone issues)
const holiday = holidays.find(h => { const holiday = holidays.find(h => {
return h.date.toISOString().split('T')[0] === dateStr; return h.date.getFullYear() === year &&
h.date.getMonth() === month &&
h.date.getDate() === day;
}); });
return holiday ? holiday.name : null; return holiday ? holiday.name : null;

View File

@@ -1,38 +1,18 @@
// ============================================ // ============================================
// STATE & VARIABLES // STATE & VARIABLES (additional to state.js)
// ============================================ // ============================================
let currentEditingId = null;
let datePicker = null;
let startTimePicker = null;
let endTimePicker = null;
let filterFromPicker = null;
let filterToPicker = null;
let manualStartTimePicker = null; let manualStartTimePicker = null;
// Timer state // Additional timer state (beyond state.js)
let timerInterval = null;
let timerStartTime = null;
let timerPausedDuration = 0; // Total paused time in seconds
let isPaused = false;
let pauseTimeout = null;
let pauseStartElapsed = 0; // Elapsed time when pause started (to freeze display) let pauseStartElapsed = 0; // Elapsed time when pause started (to freeze display)
let pauseEndTime = 0; // Timestamp when pause will end (for countdown) let pauseEndTime = 0; // Timestamp when pause will end (for countdown)
let timerStartTimeString = ''; // Start time as string (HH:MM) for display let timerStartTimeString = ''; // Start time as string (HH:MM) for display
let currentEntryId = null; // ID of today's entry being timed
// Current month display state
let displayYear = new Date().getFullYear();
let displayMonth = new Date().getMonth(); // 0-11
// Current view state // Current view state
let currentView = 'monthly'; // 'monthly' or 'filter' let currentView = 'monthly'; // 'monthly' or 'filter'
let currentFilterFrom = null; let currentFilterFrom = null;
let currentFilterTo = null; let currentFilterTo = null;
// Bulk edit state
let bulkEditMode = false;
let selectedEntries = new Set();
// Settings state // Settings state
let currentBundesland = 'BW'; // Default: Baden-Württemberg let currentBundesland = 'BW'; // Default: Baden-Württemberg
let totalVacationDays = 30; // Default vacation days per year let totalVacationDays = 30; // Default vacation days per year
@@ -2109,7 +2089,10 @@ async function bulkExportPDF() {
// Count workdays based on selected entries only // Count workdays based on selected entries only
selectedDates.forEach(dateISO => { selectedDates.forEach(dateISO => {
const dateObj = new Date(dateISO); // Parse date correctly to avoid timezone issues
const [year, month, day] = dateISO.split('-').map(Number);
const dateObj = new Date(year, month - 1, day);
const isVacation = vacationDaysSet.has(dateISO); const isVacation = vacationDaysSet.has(dateISO);
const isFlextime = flextimeDaysSet.has(dateISO); const isFlextime = flextimeDaysSet.has(dateISO);
const isWeekendHoliday = isWeekendOrHoliday(dateObj); const isWeekendHoliday = isWeekendOrHoliday(dateObj);
@@ -2975,8 +2958,19 @@ async function handleExportPDF() {
// Calculate statistics // Calculate statistics
const today = new Date(); const today = new Date();
today.setHours(23, 59, 59, 999); // Set to end of day to include today
// Count workdays (excluding weekends and holidays, only up to today) // Find the last entry date to calculate workdays up to (parse correctly to avoid timezone issues)
let lastEntryDate = today;
if (entries.length > 0) {
const sortedEntries = entries.sort((a, b) => b.date.localeCompare(a.date));
const lastDateStr = sortedEntries[0].date; // "2025-10-22"
const [year, month, day] = lastDateStr.split('-').map(Number);
lastEntryDate = new Date(year, month - 1, day, 23, 59, 59, 999);
}
// Count workdays (excluding weekends and holidays, up to last entry or today, whichever is later)
const countUntil = lastEntryDate > today ? lastEntryDate : today;
let workdaysPassed = 0; let workdaysPassed = 0;
let totalWorkdaysInMonth = 0; let totalWorkdaysInMonth = 0;
@@ -3008,13 +3002,13 @@ async function handleExportPDF() {
if (!isWeekendHoliday && !isVacation) { if (!isWeekendHoliday && !isVacation) {
// Normal workday (excluding vacation days) // Normal workday (excluding vacation days)
totalWorkdaysInMonth++; totalWorkdaysInMonth++;
if (dateObj <= today) { if (dateObj <= countUntil) {
workdaysPassed++; workdaysPassed++;
} }
} else if (isFlextime && isWeekendHoliday) { } else if (isFlextime && isWeekendHoliday) {
// Flextime on weekend/holiday counts as additional workday // Flextime on weekend/holiday counts as additional workday
totalWorkdaysInMonth++; totalWorkdaysInMonth++;
if (new Date(dateISO) <= today) { if (new Date(dateISO) <= countUntil) {
workdaysPassed++; workdaysPassed++;
} }
} }
@@ -3037,7 +3031,7 @@ async function handleExportPDF() {
entries.forEach(entry => { entries.forEach(entry => {
const entryDate = new Date(entry.date); const entryDate = new Date(entry.date);
if (entryDate <= today) { if (entryDate <= countUntil) {
if (!entry.entryType || entry.entryType === 'work') { if (!entry.entryType || entry.entryType === 'work') {
totalNetHours += entry.netHours; totalNetHours += entry.netHours;
workEntriesCount++; workEntriesCount++;

View File

@@ -3,49 +3,49 @@
*/ */
// Modal state // Modal state
export let currentEditingId = null; let currentEditingId = null;
export let datePicker = null; let datePicker = null;
export let startTimePicker = null; let startTimePicker = null;
export let endTimePicker = null; let endTimePicker = null;
export let filterFromPicker = null; let filterFromPicker = null;
export let filterToPicker = null; let filterToPicker = null;
// Timer state // Timer state
export let timerInterval = null; let timerInterval = null;
export let timerStartTime = null; let timerStartTime = null;
export let timerPausedDuration = 0; // Total paused time in seconds let timerPausedDuration = 0; // Total paused time in seconds
export let isPaused = false; let isPaused = false;
export let pauseTimeout = null; let pauseTimeout = null;
export let currentEntryId = null; // ID of today's entry being timed let currentEntryId = null; // ID of today's entry being timed
// Current month display state // Current month display state
export let displayYear = new Date().getFullYear(); let displayYear = new Date().getFullYear();
export let displayMonth = new Date().getMonth(); // 0-11 let displayMonth = new Date().getMonth(); // 0-11
// Bulk edit state // Bulk edit state
export let bulkEditMode = false; let bulkEditMode = false;
export let selectedEntries = new Set(); let selectedEntries = new Set();
// Setters for state mutations // Setters for state mutations
export function setCurrentEditingId(id) { currentEditingId = id; } function setCurrentEditingId(id) { currentEditingId = id; }
export function setDatePicker(picker) { datePicker = picker; } function setDatePicker(picker) { datePicker = picker; }
export function setStartTimePicker(picker) { startTimePicker = picker; } function setStartTimePicker(picker) { startTimePicker = picker; }
export function setEndTimePicker(picker) { endTimePicker = picker; } function setEndTimePicker(picker) { endTimePicker = picker; }
export function setFilterFromPicker(picker) { filterFromPicker = picker; } function setFilterFromPicker(picker) { filterFromPicker = picker; }
export function setFilterToPicker(picker) { filterToPicker = picker; } function setFilterToPicker(picker) { filterToPicker = picker; }
export function setTimerInterval(interval) { timerInterval = interval; } function setTimerInterval(interval) { timerInterval = interval; }
export function setTimerStartTime(time) { timerStartTime = time; } function setTimerStartTime(time) { timerStartTime = time; }
export function setTimerPausedDuration(duration) { timerPausedDuration = duration; } function setTimerPausedDuration(duration) { timerPausedDuration = duration; }
export function setIsPaused(paused) { isPaused = paused; } function setIsPaused(paused) { isPaused = paused; }
export function setPauseTimeout(timeout) { pauseTimeout = timeout; } function setPauseTimeout(timeout) { pauseTimeout = timeout; }
export function setCurrentEntryId(id) { currentEntryId = id; } function setCurrentEntryId(id) { currentEntryId = id; }
export function setDisplayYear(year) { displayYear = year; } function setDisplayYear(year) { displayYear = year; }
export function setDisplayMonth(month) { displayMonth = month; } function setDisplayMonth(month) { displayMonth = month; }
export function setBulkEditMode(mode) { bulkEditMode = mode; } function setBulkEditMode(mode) { bulkEditMode = mode; }
export function clearSelectedEntries() { selectedEntries.clear(); } function clearSelectedEntries() { selectedEntries.clear(); }
export function addSelectedEntry(id) { selectedEntries.add(id); } function addSelectedEntry(id) { selectedEntries.add(id); }
export function removeSelectedEntry(id) { selectedEntries.delete(id); } function removeSelectedEntry(id) { selectedEntries.delete(id); }
export function hasSelectedEntry(id) { return selectedEntries.has(id); } function hasSelectedEntry(id) { return selectedEntries.has(id); }