import { useState, useRef } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { Database, Download, Upload, Trash2, RefreshCw, HardDrive, Clock, FileText, FolderOpen, Archive, AlertTriangle, Bomb } from 'lucide-react'; import { backupApi, BackupInfo, getAccessToken } from '../../services/api'; import { useAuth } from '../../context/AuthContext'; import Button from '../../components/ui/Button'; export default function DatabaseBackup() { const [showRestoreConfirm, setShowRestoreConfirm] = useState(null); const [showDeleteConfirm, setShowDeleteConfirm] = useState(null); const [showFactoryResetConfirm, setShowFactoryResetConfirm] = useState(false); const [factoryResetConfirmText, setFactoryResetConfirmText] = useState(''); const [uploadError, setUploadError] = useState(null); const fileInputRef = useRef(null); const queryClient = useQueryClient(); const { logout } = useAuth(); // Backups laden const { data: backupsData, isLoading } = useQuery({ queryKey: ['backups'], queryFn: () => backupApi.list(), }); const backups = backupsData?.data || []; // Backup erstellen const createMutation = useMutation({ mutationFn: () => backupApi.create(), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['backups'] }); }, }); // Backup wiederherstellen const restoreMutation = useMutation({ mutationFn: (name: string) => backupApi.restore(name), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['backups'] }); setShowRestoreConfirm(null); }, }); // Backup löschen const deleteMutation = useMutation({ mutationFn: (name: string) => backupApi.delete(name), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['backups'] }); setShowDeleteConfirm(null); }, }); // Backup hochladen const uploadMutation = useMutation({ mutationFn: (file: File) => backupApi.upload(file), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['backups'] }); setUploadError(null); if (fileInputRef.current) { fileInputRef.current.value = ''; } }, onError: (error: any) => { setUploadError(error.message || 'Upload fehlgeschlagen'); }, }); // Werkseinstellungen const factoryResetMutation = useMutation({ mutationFn: () => backupApi.factoryReset(), onSuccess: () => { setShowFactoryResetConfirm(false); setFactoryResetConfirmText(''); // Nach Factory Reset ausloggen logout(); }, }); // Datei-Upload Handler const handleFileSelect = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (file) { if (!file.name.endsWith('.zip')) { setUploadError('Nur ZIP-Dateien sind erlaubt'); return; } setUploadError(null); uploadMutation.mutate(file); } }; // Download mit Auth-Token const handleDownload = async (name: string) => { const token = getAccessToken(); const url = backupApi.getDownloadUrl(name); try { const response = await fetch(url, { headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error('Download fehlgeschlagen'); } // Blob erstellen und herunterladen const blob = await response.blob(); const downloadUrl = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = downloadUrl; a.download = `opencrm-backup-${name}.zip`; document.body.appendChild(a); a.click(); document.body.removeChild(a); window.URL.revokeObjectURL(downloadUrl); } catch (error: any) { console.error('Download error:', error); } }; // Formatierung const formatDate = (timestamp: string) => { return new Date(timestamp).toLocaleString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', }); }; const formatSize = (bytes: number) => { if (bytes < 1024) return `${bytes} B`; if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; }; return (
{/* Header */}

Datenbank & Zurücksetzen

Backups erstellen, wiederherstellen oder auf Werkseinstellungen zurücksetzen.

{/* Upload Button */} {/* Create Button */}
{/* Upload Error */} {uploadError && (
{uploadError}
)} {/* Info-Box */}

Hinweise zur Datensicherung

  • Backups enthalten alle Datenbankdaten und hochgeladene Dokumente
  • Erstellen Sie vor Datenbankmigrationen immer ein Backup
  • Backups können als ZIP heruntergeladen und auf einem anderen System wiederhergestellt werden
  • Bei der Wiederherstellung werden bestehende Daten mit dem Backup-Stand überschrieben
{/* Backup-Liste */}

Verfügbare Backups

{isLoading ? (
) : backups.length === 0 ? (

Keine Backups vorhanden

Erstellen Sie Ihr erstes Backup

) : (
{backups.map((backup: BackupInfo) => (
{backup.name} {formatDate(backup.timestamp)}
{backup.totalRecords.toLocaleString('de-DE')} Datensätze {formatSize(backup.sizeBytes)} {backup.hasUploads && ( Dokumente ({formatSize(backup.uploadSizeBytes)}) )}
{/* Tabellen-Details (kollabiert) */}
Tabellen anzeigen ({backup.tables.filter(t => t.count > 0).length} mit Daten)
{backup.tables .filter(t => t.count > 0) .map(t => ( {t.table}: {t.count} ))}
{/* Aktionen */}
))}
)}
{/* Wiederherstellungs-Bestätigung */} {showRestoreConfirm && (

Backup wiederherstellen?

Möchten Sie das Backup {showRestoreConfirm} wirklich wiederherstellen?

Achtung: Bestehende Daten und Dokumente werden mit dem Backup-Stand überschrieben. Dies kann nicht rückgängig gemacht werden.

)} {/* Lösch-Bestätigung */} {showDeleteConfirm && (

Backup löschen?

Möchten Sie das Backup {showDeleteConfirm} wirklich löschen? Dies kann nicht rückgängig gemacht werden.

)} {/* Werkseinstellungen */}

Werkseinstellungen

Setzt das System auf den Ausgangszustand zurück. Alle Daten werden unwiderruflich gelöscht - Kunden, Verträge, Benutzer, Dokumente und Einstellungen. Nur die hier gespeicherten Backups bleiben erhalten.

  • Alle Kunden und Verträge werden gelöscht
  • Alle Benutzer werden gelöscht
  • Alle hochgeladenen Dokumente werden gelöscht
  • Ein neuer Admin-Benutzer wird erstellt (admin@admin.com / admin)
  • Backups bleiben erhalten und können danach wiederhergestellt werden
{/* Werkseinstellungen-Bestätigung */} {showFactoryResetConfirm && (

Wirklich auf Werkseinstellungen zurücksetzen?

Diese Aktion löscht alle Daten unwiderruflich. Es gibt kein Zurück!

Geben Sie zur Bestätigung LÖSCHEN ein:

setFactoryResetConfirmText(e.target.value)} placeholder="LÖSCHEN" className="w-full px-3 py-2 border border-gray-300 rounded-lg mb-4 focus:ring-2 focus:ring-red-500 focus:border-red-500" />
)}
); }