import React from 'react';
import { useTranslation } from 'react-i18next';
import {
HardDrive,
Database,
FileArchive,
Image,
Clock,
CheckCircle,
AlertCircle,
TrendingUp,
Shield,
Server,
Cloud,
Calendar,
Play,
Loader2,
AlertTriangle,
Info
} from 'lucide-react';
import { format, formatDistanceToNow } from 'date-fns';
import { Card, Button } from '../common';
const StatCard = ({ icon: Icon, label, value, color = 'blue', subtext }) => (
{label}
{value}
{subtext && (
{subtext}
)}
);
const formatBytes = (bytes) => {
if (!bytes) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
};
export const BackupDashboard = ({ status, config, onRunBackup, isBackupRunning }) => {
const { t } = useTranslation();
const lastBackup = status?.lastBackup;
const statistics = lastBackup?.statistics || {};
const isConfigured = config && config.backup_destination_type;
const isEnabled = config?.backup_enabled;
// Calculate backup health score
const getHealthScore = () => {
if (!lastBackup) return { score: 0, status: 'critical', message: t('backup.dashboard.healthMessages.noBackups') };
const hoursSinceBackup = (Date.now() - new Date(lastBackup.created_at)) / (1000 * 60 * 60);
if (lastBackup.status === 'failed') {
return { score: 0, status: 'critical', message: t('backup.dashboard.healthMessages.lastBackupFailed') };
}
if (hoursSinceBackup < 24) {
return { score: 100, status: 'excellent', message: t('backup.dashboard.healthMessages.upToDate') };
} else if (hoursSinceBackup < 48) {
return { score: 75, status: 'good', message: t('backup.dashboard.healthMessages.recent') };
} else if (hoursSinceBackup < 168) { // 1 week
return { score: 50, status: 'warning', message: t('backup.dashboard.healthMessages.gettingOld') };
} else {
return { score: 25, status: 'critical', message: t('backup.dashboard.healthMessages.outdated') };
}
};
const health = getHealthScore();
const healthColors = {
excellent: 'green',
good: 'blue',
warning: 'amber',
critical: 'red'
};
return (
{/* Configuration Alert */}
{!isConfigured && (
{t('backup.dashboard.notConfigured.title')}
{t('backup.dashboard.notConfigured.message')}
)}
{/* Health Score Card */}
{t('backup.dashboard.health.title')}
{health.status.charAt(0).toUpperCase() + health.status.slice(1)}
{health.message}
{lastBackup && (
Last successful backup: {formatDistanceToNow(new Date(lastBackup.created_at), { addSuffix: true })}
)}
{isBackupRunning ? (
<>
{t('backup.dashboard.actions.running')}
>
) : (
<>
{t('backup.dashboard.actions.runBackupNow')}
>
)}
{/* Statistics Grid */}
{/* Recent Activity */}
{status?.recentBackups && status.recentBackups.length > 0 && (
{t('backup.dashboard.recentActivity.title')}
{status.recentBackups.slice(0, 5).map((backup) => (
{backup.status === 'completed' ? (
) : backup.status === 'failed' ? (
) : (
)}
{t('backup.dashboard.backupType', { type: backup.backup_type })}
{format(new Date(backup.created_at), 'PPp')}
{formatBytes(backup.statistics?.total_size || 0)}
{backup.statistics?.files_processed || 0} files
))}
)}
{/* Storage Status */}
{t('backup.dashboard.coverage.title')}
Database
{statistics.database_backed_up ? t('backup.dashboard.coverage.included') : t('backup.dashboard.coverage.excluded')}
{t('backup.configuration.whatToBackup.photos')}
{statistics.photos_backed_up || 0} {t('common.of')} {statistics.total_photos || 0}
{t('backup.configuration.whatToBackup.archives')}
{statistics.archives_backed_up || 0} {t('backup.dashboard.stats.files')}
{t('backup.dashboard.storageDestination')}
{config?.backup_destination_type === 's3' ? (
) : config?.backup_destination_type === 'rsync' ? (
) : (
)}
{config?.backup_destination_type
? t(`backup.configuration.destinationTypes.${config.backup_destination_type}.name`)
: t('backup.dashboard.notConfigured.title')}
{config?.backup_destination_type === 's3' && config?.backup_s3_bucket
? `Bucket: ${config.backup_s3_bucket}`
: config?.backup_destination_type === 'local' && config?.backup_destination_path
? `Path: ${config.backup_destination_path}`
: config?.backup_destination_type === 'rsync' && config?.backup_rsync_host
? `Host: ${config.backup_rsync_host}`
: t('backup.dashboard.noDestinationSet')}
{config?.backup_retention_days && (
{t('backup.configuration.schedule.retentionDays')} {config.backup_retention_days} {t('backup.configuration.schedule.retentionHelp').replace('days (older backups will be automatically deleted)', '')}
)}
);
};