2025-12-21 03:43:37 +02:00

178 lines
5.9 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState, useEffect } from 'react';
import { triggerBackup, listBackups, restoreBackup } from '../backupApi';
import Modal from './Modal';
function AdminPanel({ onShowToast }) {
const [backups, setBackups] = useState([]);
const [loading, setLoading] = useState(false);
const [restoreModal, setRestoreModal] = useState({ isOpen: false, filename: '' });
const [restoring, setRestoring] = useState(false);
useEffect(() => {
loadBackups();
}, []);
const loadBackups = async () => {
try {
setLoading(true);
const data = await listBackups();
setBackups(data.backups || []);
} catch (error) {
onShowToast(error.message || 'שגיאה בטעינת גיבויים', 'error');
} finally {
setLoading(false);
}
};
const handleCreateBackup = async () => {
try {
setLoading(true);
const result = await triggerBackup();
onShowToast('גיבוי נוצר בהצלחה! 📦', 'success');
loadBackups(); // Refresh list
} catch (error) {
onShowToast(error.message || 'שגיאה ביצירת גיבוי', 'error');
} finally {
setLoading(false);
}
};
const handleRestoreClick = (filename) => {
setRestoreModal({ isOpen: true, filename });
};
const handleRestoreConfirm = async () => {
console.log('Restore confirm clicked, filename:', restoreModal.filename);
setRestoreModal({ isOpen: false, filename: '' });
setRestoring(true);
try {
console.log('Starting restore...');
const result = await restoreBackup(restoreModal.filename);
console.log('Restore result:', result);
onShowToast('שחזור הושלם בהצלחה! ♻️ מרענן את הדף...', 'success');
// Refresh page after 2 seconds to reload all data
setTimeout(() => {
window.location.reload();
}, 2000);
} catch (error) {
console.error('Restore error:', error);
onShowToast(error.message || 'שגיאה בשחזור גיבוי', 'error');
setRestoring(false);
}
};
const formatBytes = (bytes) => {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i];
};
const formatDate = (isoString) => {
const date = new Date(isoString);
return date.toLocaleString('he-IL', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
});
};
return (
<div className="admin-panel">
<div className="admin-header">
<h2>ניהול גיבויים 🛡</h2>
<button
className="btn primary"
onClick={handleCreateBackup}
disabled={loading}
>
{loading ? 'יוצר גיבוי...' : 'צור גיבוי חדש'}
</button>
</div>
{loading && backups.length === 0 ? (
<div className="loading">טוען גיבויים...</div>
) : backups.length === 0 ? (
<div className="empty-state">אין גיבויים זמינים</div>
) : (
<div className="backups-list">
<table className="backups-table">
<thead>
<tr>
<th className="col-filename">קובץ</th>
<th className="col-date">תאריך</th>
<th className="col-size">גודל</th>
<th className="col-actions">פעולות</th>
</tr>
</thead>
<tbody>
{backups.map((backup) => (
<tr key={backup.filename}>
<td className="filename">{backup.filename}</td>
<td className="date">{formatDate(backup.last_modified)}</td>
<td className="size">{formatBytes(backup.size)}</td>
<td className="actions">
<button
className="btn ghost small"
onClick={() => handleRestoreClick(backup.filename)}
disabled={loading}
>
שחזר
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
)}
<Modal
isOpen={restoreModal.isOpen || restoring}
onClose={() => !restoring && setRestoreModal({ isOpen: false, filename: '' })}
title={restoring ? "⏳ משחזר גיבוי..." : "⚠️ אישור שחזור גיבוי"}
>
{restoring ? (
<div className="restore-progress">
<div className="progress-bar-container">
<div className="progress-bar-fill"></div>
</div>
<p className="progress-text">מוריד גיבוי...</p>
<p className="progress-text">משחזר מסד נתונים...</p>
<p className="progress-text-muted">אנא המתן, התהליך עשוי לקחת מספר דקות</p>
</div>
) : (
<div className="restore-warning">
<p>פעולה זו תמחק את כל הנתונים הנוכחיים!</p>
<p>האם אתה בטוח שברצונך לשחזר מהגיבוי:</p>
<p className="filename-highlight">{restoreModal.filename}</p>
<div className="modal-actions">
<button
className="btn ghost"
onClick={() => setRestoreModal({ isOpen: false, filename: '' })}
disabled={loading}
>
ביטול
</button>
<button
className="btn danger"
onClick={handleRestoreConfirm}
disabled={loading}
>
שחזר
</button>
</div>
</div>
)}
</Modal>
</div>
);
}
export default AdminPanel;