'use client'; import { useState, useEffect, useCallback } from 'react'; import type { BackupItem } from '@/app/api/admin/backups/route'; import * as Icons from './Icons'; import { useScrollLock } from './useScrollLock'; interface Props { isOpen: boolean; onClose: () => void; onRestoreSuccess: () => void; } export default function BackupManagerModal({ isOpen, onClose, onRestoreSuccess }: Props) { const [activeTab, setActiveTab] = useState<'gallery' | 'settings'>('gallery'); const [showAllBackups, setShowAllBackups] = useState(false); const [backups, setBackups] = useState<{ gallery: BackupItem[]; settings: BackupItem[] }>({ gallery: [], settings: [], }); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [restoringFilename, setRestoringFilename] = useState(null); const [confirmFilename, setConfirmFilename] = useState(null); const [successMsg, setSuccessMsg] = useState(null); const fetchBackups = useCallback(async () => { setLoading(true); setError(null); try { const res = await fetch('/api/admin/backups'); if (!res.ok) { throw new Error('Failed to fetch backup history'); } const data = await res.json(); setBackups(data.backups || { gallery: [], settings: [] }); } catch (err: any) { setError(err.message || 'Error loading backups'); } finally { setLoading(false); } }, []); useEffect(() => { if (isOpen) { fetchBackups(); setConfirmFilename(null); setSuccessMsg(null); setShowAllBackups(false); } }, [isOpen, fetchBackups]); useScrollLock(isOpen); if (!isOpen) return null; async function handleRestore(filename: string) { setRestoringFilename(filename); setError(null); setSuccessMsg(null); try { const res = await fetch('/api/admin/backups', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ backupFilename: filename }), }); const data = await res.json(); if (!res.ok) { throw new Error(data.error || 'Failed to restore backup'); } setSuccessMsg(`Backup restored successfully! (${filename})`); setConfirmFilename(null); await fetchBackups(); onRestoreSuccess(); } catch (err: any) { setError(err.message || 'Error restoring backup'); } finally { setRestoringFilename(null); } } const currentList = backups[activeTab] || []; const INITIAL_VISIBLE_COUNT = 3; const visibleList = showAllBackups ? currentList : currentList.slice(0, INITIAL_VISIBLE_COUNT); const hiddenCount = currentList.length - INITIAL_VISIBLE_COUNT; return (
e.stopPropagation()}>

Backup History & Restoration

Restore previous states of your configuration files with 1-click.

{/* Tab Selection */}
{/* Status Messages */} {error &&
{error}
} {successMsg &&
{successMsg}
} {/* Confirmation Modal Section */} {confirmFilename && (
Confirm Restoration

Are you sure you want to restore {confirmFilename}? A safety snapshot of your current state will be created automatically before reverting.

)} {/* Backup List Content */}
{loading ? (
Loading backups...
) : currentList.length === 0 ? (
No backups available yet for {activeTab}.yaml
) : (
{visibleList.map((item) => { const dateObj = item.timestamp ? new Date(item.timestamp) : null; const formattedDate = dateObj && !isNaN(dateObj.getTime()) ? dateObj.toLocaleString('de-DE', { dateStyle: 'medium', timeStyle: 'medium', }) : item.filename; return (
{formattedDate} {item.isPreRestore && ( Pre-Restore Snapshot )}
{item.filename}
); })} {currentList.length > INITIAL_VISIBLE_COUNT && ( )}
)}
); }