import React, { useState, useEffect, useRef } from 'react' import { backupApi } from '../../api/client' import { useToast } from '../shared/Toast' import { Download, Trash2, Plus, RefreshCw, RotateCcw, Upload, Clock, Check, HardDrive, AlertTriangle } from 'lucide-react' import { useTranslation } from '../../i18n' const INTERVAL_OPTIONS = [ { value: 'hourly', labelKey: 'backup.interval.hourly' }, { value: 'daily', labelKey: 'backup.interval.daily' }, { value: 'weekly', labelKey: 'backup.interval.weekly' }, { value: 'monthly', labelKey: 'backup.interval.monthly' }, ] const KEEP_OPTIONS = [ { value: 1, labelKey: 'backup.keep.1day' }, { value: 3, labelKey: 'backup.keep.3days' }, { value: 7, labelKey: 'backup.keep.7days' }, { value: 14, labelKey: 'backup.keep.14days' }, { value: 30, labelKey: 'backup.keep.30days' }, { value: 0, labelKey: 'backup.keep.forever' }, ] export default function BackupPanel() { const [backups, setBackups] = useState([]) const [isLoading, setIsLoading] = useState(false) const [isCreating, setIsCreating] = useState(false) const [restoringFile, setRestoringFile] = useState(null) const [isUploading, setIsUploading] = useState(false) const [autoSettings, setAutoSettings] = useState({ enabled: false, interval: 'daily', keep_days: 7 }) const [autoSettingsSaving, setAutoSettingsSaving] = useState(false) const [autoSettingsDirty, setAutoSettingsDirty] = useState(false) const [restoreConfirm, setRestoreConfirm] = useState(null) // { type: 'file'|'upload', filename, file? } const fileInputRef = useRef(null) const toast = useToast() const { t, language, locale } = useTranslation() const loadBackups = async () => { setIsLoading(true) try { const data = await backupApi.list() setBackups(data.backups || []) } catch { toast.error(t('backup.toast.loadError')) } finally { setIsLoading(false) } } const loadAutoSettings = async () => { try { const data = await backupApi.getAutoSettings() setAutoSettings(data.settings) } catch {} } useEffect(() => { loadBackups(); loadAutoSettings() }, []) const handleCreate = async () => { setIsCreating(true) try { await backupApi.create() toast.success(t('backup.toast.created')) await loadBackups() } catch { toast.error(t('backup.toast.createError')) } finally { setIsCreating(false) } } const handleRestore = (filename) => { setRestoreConfirm({ type: 'file', filename }) } const handleUploadRestore = (e) => { const file = e.target.files?.[0] if (!file) return e.target.value = '' setRestoreConfirm({ type: 'upload', filename: file.name, file }) } const executeRestore = async () => { if (!restoreConfirm) return const { type, filename, file } = restoreConfirm setRestoreConfirm(null) if (type === 'file') { setRestoringFile(filename) try { await backupApi.restore(filename) toast.success(t('backup.toast.restored')) setTimeout(() => window.location.reload(), 1500) } catch (err) { toast.error(err.response?.data?.error || t('backup.toast.restoreError')) setRestoringFile(null) } } else { setIsUploading(true) try { await backupApi.uploadRestore(file) toast.success(t('backup.toast.restored')) setTimeout(() => window.location.reload(), 1500) } catch (err) { toast.error(err.response?.data?.error || t('backup.toast.uploadError')) setIsUploading(false) } } } const handleDelete = async (filename) => { if (!confirm(t('backup.confirm.delete', { name: filename }))) return try { await backupApi.delete(filename) toast.success(t('backup.toast.deleted')) setBackups(prev => prev.filter(b => b.filename !== filename)) } catch { toast.error(t('backup.toast.deleteError')) } } const handleAutoSettingsChange = (key, value) => { setAutoSettings(prev => ({ ...prev, [key]: value })) setAutoSettingsDirty(true) } const handleSaveAutoSettings = async () => { setAutoSettingsSaving(true) try { const data = await backupApi.setAutoSettings(autoSettings) setAutoSettings(data.settings) setAutoSettingsDirty(false) toast.success(t('backup.toast.settingsSaved')) } catch { toast.error(t('backup.toast.settingsError')) } finally { setAutoSettingsSaving(false) } } const formatSize = (bytes) => { if (!bytes) return '-' if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB` return `${(bytes / 1024 / 1024).toFixed(1)} MB` } const formatDate = (dateStr) => { if (!dateStr) return '-' try { return new Date(dateStr).toLocaleString(locale, { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', }) } catch { return dateStr } } const isAuto = (filename) => filename.startsWith('auto-backup-') return (
{t('backup.subtitle')}
{t('backup.empty')}
{backup.filename}
{isAuto(backup.filename) && ( Auto )}{t('backup.auto.subtitle')}
{restoreConfirm.filename}
{t('backup.restoreWarning')}