import React, { useState, useRef } from 'react' import api from '../api.js' import { Download, Upload, Database, AlertTriangle, Check, RefreshCw, FileJson, ShieldAlert, Info } from 'lucide-react' export default function Maintenance() { const [exporting, setExporting] = useState(false) const [importing, setImporting] = useState(false) const [importMode, setImportMode] = useState('merge') const [selectedFile, setSelectedFile] = useState(null) const [previewData, setPreviewData] = useState(null) const [previewError, setPreviewError] = useState('') const [result, setResult] = useState(null) const [error, setError] = useState('') const fileRef = useRef() // --- Export --- const handleExport = async () => { setExporting(true) setError('') try { const { data } = await api.get('/maintenance/backup', { responseType: 'blob' }) const url = URL.createObjectURL(new Blob([data], { type: 'application/json' })) const a = document.createElement('a') a.href = url a.download = `backup-${new Date().toISOString().split('T')[0]}.json` a.click() URL.revokeObjectURL(url) } catch { setError('Export failed. Please try again.') } finally { setExporting(false) } } // --- File selection & preview --- const handleFileChange = (e) => { const file = e.target.files[0] setSelectedFile(file || null) setPreviewData(null) setPreviewError('') setResult(null) setError('') if (!file) return const reader = new FileReader() reader.onload = (ev) => { try { const parsed = JSON.parse(ev.target.result) if (!parsed.fields || !parsed.contracts) { setPreviewError('Invalid backup file: missing fields or contracts data.') return } setPreviewData(parsed) } catch { setPreviewError('Could not parse file — make sure it is a valid JSON backup.') } } reader.readAsText(file) } // --- Import --- const handleImport = async () => { if (!selectedFile || !previewData) return setImporting(true) setError('') setResult(null) const formData = new FormData() formData.append('backup', selectedFile) formData.append('mode', importMode) try { const { data } = await api.post('/maintenance/restore', formData, { headers: { 'Content-Type': 'multipart/form-data' } }) setResult(data) setSelectedFile(null) setPreviewData(null) if (fileRef.current) fileRef.current.value = '' } catch (err) { setError(err.response?.data?.error || 'Import failed. Please try again.') } finally { setImporting(false) } } const clearFile = () => { setSelectedFile(null) setPreviewData(null) setPreviewError('') setResult(null) setError('') if (fileRef.current) fileRef.current.value = '' } return (
Export and import backups of your contracts and field definitions
Restore completed successfully
{result.fields_restored} field{result.fields_restored !== 1 ? 's' : ''} restored · {result.contracts_imported} contract{result.contracts_imported !== 1 ? 's' : ''} imported · Mode: {result.mode}
{error}
Download a full JSON backup of all contracts and field definitions
The backup file includes all field definitions and every contract record. It does not include user accounts or passwords.
Restore data from a previously exported backup file
Warning: Replace mode will permanently delete ALL existing contracts and field definitions before importing. This action cannot be undone.
{selectedFile.name}
{(selectedFile.size / 1024).toFixed(1)} KB
Click to select a .json backup file
{previewError}
{label}
{value}
Fields in backup: