"use client"; import { useState, useEffect } from "react"; import { motion } from "framer-motion"; import { HardDrive, Download, Trash2, RefreshCw, CheckCircle, XCircle, Loader2, Layers } from "lucide-react"; import Button from "../ui/Button"; import Modal from "../ui/Modal"; import { EmptyState } from "../ui/PageHeader"; import { formatFileSize, formatDate } from "@/lib/utils"; import toast from "react-hot-toast"; interface BackupData { id: string; status: string; type: string; size: number; path: string | null; startedAt: string; completedAt: string | null; } export default function BackupPanel() { const [backups, setBackups] = useState([]); const [loading, setLoading] = useState(true); const [creating, setCreating] = useState<"full" | "incremental" | null>(null); const [toDelete, setToDelete] = useState(null); const fetchBackups = async () => { const res = await fetch("/api/backup"); if (res.ok) setBackups(await res.json()); setLoading(false); }; useEffect(() => { fetchBackups(); }, []); const createBackup = async (type: "full" | "incremental") => { setCreating(type); try { const res = await fetch("/api/backup", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ type }) }); if (res.ok) { toast.success(`Backup ${type === "full" ? "complet" : "incrémental"} créé`); fetchBackups(); } else toast.error("Échec du backup"); } catch { toast.error("Erreur réseau"); } setCreating(null); }; const deleteBackup = async () => { if (!toDelete) return; const res = await fetch("/api/backup", { method: "DELETE", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ id: toDelete.id }) }); setToDelete(null); if (res.ok) { toast.success("Backup supprimé"); fetchBackups(); } else toast.error("Suppression impossible"); }; const statusIcon = (status: string) => { if (status === "completed") return ; if (status === "failed") return ; return ; }; const totalSize = backups.reduce((s, b) => s + (b.size || 0), 0); return (

Sauvegardes manuelles

{backups.length} backup{backups.length !== 1 ? "s" : ""} · {formatFileSize(totalSize)} au total

{loading ? (
{[0, 1, 2].map((i) => (
))}
) : backups.length === 0 ? ( ) : (
{backups.map((backup, i) => (
{statusIcon(backup.status)}

{formatDate(backup.startedAt)} {backup.type === "full" ? "Complet" : "Incrémental"}

{backup.size > 0 ? formatFileSize(backup.size) : "—"} {backup.completedAt && ` · terminé à ${new Date(backup.completedAt).toLocaleTimeString("fr-CA", { hour: "2-digit", minute: "2-digit" })}`} {backup.status === "failed" && " · échec"}

))}
)} setToDelete(null)} title="Supprimer ce backup ?" description={toDelete ? `${formatDate(toDelete.startedAt)} · ${formatFileSize(toDelete.size || 0)}` : undefined} footer={<>} >

L'archive sera effacée du disque. Cette action est irréversible.

); }