diff --git a/public/js/main.js b/public/js/main.js
index 1ad10cd..5ea91a9 100644
--- a/public/js/main.js
+++ b/public/js/main.js
@@ -1352,6 +1352,8 @@ async function updateStatistics(entries) {
.map(e => e.date)
);
+ let futureFlextimeDays = 0; // Count future flextime days in current month
+
for (let day = 1; day <= lastDay; day++) {
const dateObj = new Date(currentYear, currentMonth, day);
const year = dateObj.getFullYear();
@@ -1363,13 +1365,26 @@ async function updateStatistics(entries) {
const isFlextime = flextimeDays.has(dateISO);
const isWeekendHoliday = isWeekendOrHoliday(dateObj);
- if (!isWeekendHoliday && !isVacation) {
- // Normal workday (excluding vacation days)
+ if (!isWeekendHoliday && !isVacation && !isFlextime) {
+ // Normal workday (excluding vacation and flextime days)
totalWorkdaysInMonth++;
workdaysCount++;
if (dateObj <= today) {
workdaysPassed++;
}
+ } else if (!isWeekendHoliday && !isVacation && isFlextime) {
+ // Flextime on a workday - still counts as workday in calendar
+ totalWorkdaysInMonth++;
+ workdaysCount++;
+ if (dateObj <= today) {
+ workdaysPassed++;
+ } else {
+ // Future flextime in current month
+ const isCurrentMonth = currentYear === today.getFullYear() && currentMonth === today.getMonth();
+ if (isCurrentMonth) {
+ futureFlextimeDays++;
+ }
+ }
} else if (isFlextime && isWeekendHoliday) {
// Flextime on weekend/holiday counts as additional workday
totalWorkdaysInMonth++;
@@ -1380,7 +1395,7 @@ async function updateStatistics(entries) {
// Vacation days are excluded from all counts
}
- // Calculate target hours (8h per workday passed)
+ // Calculate target hours (8h per workday passed, no reduction)
const targetHours = workdaysPassed * 8;
// Calculate actual hours worked (only up to today)
@@ -1406,7 +1421,10 @@ async function updateStatistics(entries) {
}
// Calculate balance for current month
- const balance = actualHours - targetHours;
+ let balance = actualHours - targetHours;
+
+ // Subtract future flextime days from balance (they consume flextime)
+ balance -= (futureFlextimeDays * 8);
// Calculate previous month balance
const previousBalance = await calculatePreviousBalance();
@@ -1425,6 +1443,33 @@ async function updateStatistics(entries) {
document.getElementById('statActualHours').textContent = actualHours.toFixed(1) + 'h';
document.getElementById('statWorkdays').textContent = `${workEntriesCount}/${totalWorkdaysInMonth}`;
+ // Show/hide flextime hint icons
+ const balanceFlextimeHint = document.getElementById('balanceFlextimeHint');
+ const totalBalanceFlextimeHint = document.getElementById('totalBalanceFlextimeHint');
+
+ if (futureFlextimeDays > 0) {
+ const tooltipText = `Inkl. ${futureFlextimeDays} geplanter Gleitzeittag${futureFlextimeDays > 1 ? 'e' : ''} (-${futureFlextimeDays * 8}h)`;
+
+ balanceFlextimeHint.classList.remove('hidden');
+ totalBalanceFlextimeHint.classList.remove('hidden');
+
+ // Set title attribute before re-initializing icons
+ balanceFlextimeHint.setAttribute('title', tooltipText);
+ totalBalanceFlextimeHint.setAttribute('title', tooltipText);
+
+ // Re-initialize icons
+ if (typeof lucide !== 'undefined' && lucide.createIcons) {
+ lucide.createIcons();
+ }
+
+ // Re-apply title after icon initialization (in case it was cleared)
+ balanceFlextimeHint.setAttribute('title', tooltipText);
+ totalBalanceFlextimeHint.setAttribute('title', tooltipText);
+ } else {
+ balanceFlextimeHint.classList.add('hidden');
+ totalBalanceFlextimeHint.classList.add('hidden');
+ }
+
// Current month balance
const balanceElement = document.getElementById('statBalance');
balanceElement.textContent = (balance >= 0 ? '+' : '') + balance.toFixed(1) + 'h';
@@ -2651,6 +2696,90 @@ async function handleBundeslandChange(event) {
const newBundesland = event.target.value;
const oldBundesland = currentBundesland;
+ // Show warning with backup recommendation
+ const bundeslandNames = {
+ 'BW': 'Baden-Württemberg',
+ 'BY': 'Bayern',
+ 'BE': 'Berlin',
+ 'BB': 'Brandenburg',
+ 'HB': 'Bremen',
+ 'HH': 'Hamburg',
+ 'HE': 'Hessen',
+ 'MV': 'Mecklenburg-Vorpommern',
+ 'NI': 'Niedersachsen',
+ 'NW': 'Nordrhein-Westfalen',
+ 'RP': 'Rheinland-Pfalz',
+ 'SL': 'Saarland',
+ 'SN': 'Sachsen',
+ 'ST': 'Sachsen-Anhalt',
+ 'SH': 'Schleswig-Holstein',
+ 'TH': 'Thüringen'
+ };
+
+ // Create custom modal for bundesland change confirmation
+ const modalHTML = `
+
+
+
+
+
Achtung: Bundesland ändern
+
+
+
Sie möchten das Bundesland von ${bundeslandNames[oldBundesland]} auf ${bundeslandNames[newBundesland]} ändern.
+
Warnung: Durch die Änderung der Feiertage können bestehende Einträge betroffen sein. An Tagen, die zu Feiertagen werden, bleiben Arbeitseinträge erhalten.
+
+
Wir empfehlen ein Backup vor der Änderung:
+
+
+
+
+
+
+
+
+
+ `;
+
+ // Insert modal into DOM
+ const modalContainer = document.createElement('div');
+ modalContainer.innerHTML = modalHTML;
+ document.body.appendChild(modalContainer);
+
+ // Initialize icons in modal
+ if (typeof lucide !== 'undefined' && lucide.createIcons) {
+ lucide.createIcons();
+ }
+
+ // Handle backup button
+ document.getElementById('quickBackupBtn').addEventListener('click', async () => {
+ await exportDatabase();
+ showNotification('✓ Backup erstellt', 'success');
+ });
+
+ // Handle cancel
+ document.getElementById('cancelBundeslandChange').addEventListener('click', () => {
+ event.target.value = oldBundesland;
+ document.getElementById('bundeslandWarningModal').remove();
+ });
+
+ // Handle confirm
+ document.getElementById('confirmBundeslandChange').addEventListener('click', async () => {
+ document.getElementById('bundeslandWarningModal').remove();
+ await performBundeslandChange(newBundesland, oldBundesland, event);
+ });
+}
+
+/**
+ * Perform the actual bundesland change after confirmation
+ */
+async function performBundeslandChange(newBundesland, oldBundesland, event) {
// Check for conflicts with existing entries
const entries = await fetchEntries();
const conflicts = [];
@@ -2689,16 +2818,12 @@ async function handleBundeslandChange(event) {
}
});
- // Warn user if conflicts exist
+ // Show conflict info if exists
if (conflicts.length > 0) {
const conflictList = conflicts.map(c => ` • ${c.displayDate} (${c.holidayName})`).join('\n');
- const message = `Achtung!\n\nDie folgenden Tage werden zu Feiertagen und haben bereits Einträge:\n\n${conflictList}\n\nMöchten Sie fortfahren? Die Einträge bleiben erhalten, aber die Tage werden als Feiertage markiert.`;
-
- if (!confirm(message)) {
- // Revert selection
- event.target.value = oldBundesland;
- return;
- }
+ const message = `Folgende Tage werden zu Feiertagen und haben bereits Einträge:\n\n${conflictList}\n\nDie Einträge bleiben erhalten.`;
+ showNotification(`⚠️ ${conflicts.length} Konflikt(e) gefunden`, 'warning');
+ console.info(message);
}
// Update state and save