From 73b83198cb181ae66f814aa38e4361a8618495d4 Mon Sep 17 00:00:00 2001 From: Felix Schlusche Date: Fri, 24 Oct 2025 15:23:10 +0200 Subject: [PATCH] feat: add database export and import functionality with user confirmation --- public/index.html | 23 +++++++++ public/js/main.js | 122 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+) diff --git a/public/index.html b/public/index.html index 8a6369e..f47ca3f 100644 --- a/public/index.html +++ b/public/index.html @@ -509,6 +509,29 @@ class="w-full px-4 py-2 border border-gray-600 bg-gray-700 text-gray-100 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"> + + +
+

+ + Datenbank Verwaltung +

+
+ + + +
+

+ + Export erstellt eine JSON-Datei mit allen Einträgen und Einstellungen. Import überschreibt alle vorhandenen Daten. +

+
diff --git a/public/js/main.js b/public/js/main.js index 5915f55..503c892 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -3215,6 +3215,115 @@ async function handleExportPDF() { } } +/** + * Export entire database + */ +async function exportDatabase() { + try { + // Fetch all data + const entries = await fetchEntries(); + const settings = { + employeeName: await getSetting('employeeName') || '', + employeeId: await getSetting('employeeId') || '', + bundesland: await getSetting('bundesland') || 'NW', + vacationDaysPerYear: await getSetting('vacationDaysPerYear') || 30 + }; + + // Create export object + const exportData = { + version: '1.0', + exportDate: new Date().toISOString(), + entries: entries, + settings: settings + }; + + // Convert to JSON + const jsonString = JSON.stringify(exportData, null, 2); + const blob = new Blob([jsonString], { type: 'application/json' }); + + // Create download link + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = `zeiterfassung_backup_${new Date().toISOString().split('T')[0]}.json`; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + + showNotification(`Datenbank exportiert: ${entries.length} Einträge`, 'success'); + } catch (error) { + console.error('Error exporting database:', error); + showNotification('Fehler beim Exportieren der Datenbank', 'error'); + } +} + +/** + * Import entire database + */ +async function importDatabase(file) { + try { + const text = await file.text(); + const importData = JSON.parse(text); + + // Validate data structure + if (!importData.entries || !Array.isArray(importData.entries)) { + throw new Error('Ungültiges Datenbankformat'); + } + + // Confirm before overwriting + const confirmed = confirm( + `Möchten Sie die Datenbank wirklich importieren?\n\n` + + `Dies wird alle ${importData.entries.length} Einträge importieren und vorhandene Daten überschreiben.\n\n` + + `Export-Datum: ${new Date(importData.exportDate).toLocaleString('de-DE')}` + ); + + if (!confirmed) { + return; + } + + // Delete all existing entries + const existingEntries = await fetchEntries(); + for (const entry of existingEntries) { + await fetch(`/api/entries/${entry.id}`, { method: 'DELETE' }); + } + + // Import entries + let imported = 0; + for (const entry of importData.entries) { + try { + // Remove ID to create new entries + const { id, ...entryData } = entry; + await fetch('/api/entries', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(entryData) + }); + imported++; + } catch (err) { + console.error('Error importing entry:', err); + } + } + + // Import settings + if (importData.settings) { + await setSetting('employeeName', importData.settings.employeeName || ''); + await setSetting('employeeId', importData.settings.employeeId || ''); + await setSetting('bundesland', importData.settings.bundesland || 'NW'); + await setSetting('vacationDaysPerYear', importData.settings.vacationDaysPerYear || 30); + await loadSettings(); // Reload settings to UI + } + + // Reload view + await reloadView(); + + showNotification(`Datenbank importiert: ${imported} Einträge`, 'success'); + } catch (error) { + console.error('Error importing database:', error); + showNotification('Fehler beim Importieren der Datenbank: ' + error.message, 'error'); + } +} + /** * Show a temporary notification */ @@ -3535,6 +3644,19 @@ function initializeEventListeners() { showNotification('Personalnummer gespeichert', 'success'); }); + // Database export/import + document.getElementById('btnExportDB').addEventListener('click', exportDatabase); + document.getElementById('btnImportDB').addEventListener('click', () => { + document.getElementById('importDBFile').click(); + }); + document.getElementById('importDBFile').addEventListener('change', (e) => { + const file = e.target.files[0]; + if (file) { + importDatabase(file); + e.target.value = ''; // Reset file input + } + }); + // Close modal when clicking outside document.getElementById('entryModal').addEventListener('click', (e) => { if (e.target.id === 'entryModal') {