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 (

Maintenance

Export and import backups of your contracts and field definitions

{/* Success result */} {result && (

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}

)} {/* Global error */} {error && (

{error}

)} {/* Export section */}

Export Backup

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.

{/* Import section */}

Import Backup

Restore data from a previously exported backup file

{/* Import mode */}
{/* Replace warning */} {importMode === 'replace' && (

Warning: Replace mode will permanently delete ALL existing contracts and field definitions before importing. This action cannot be undone.

)} {/* File upload */}
fileRef.current?.click()} className={`border-2 border-dashed rounded-xl p-6 text-center cursor-pointer transition ${ selectedFile ? 'border-indigo-500/50 bg-indigo-500/5' : 'border-slate-700 hover:border-slate-600 hover:bg-slate-800/30' }`} > {selectedFile ? (

{selectedFile.name}

{(selectedFile.size / 1024).toFixed(1)} KB

) : (

Click to select a .json backup file

)}
{previewError && (

{previewError}

)}
{/* Preview */} {previewData && (

Backup Preview

{[ { label: 'Exported', value: previewData.exported_at ? new Date(previewData.exported_at).toLocaleString() : 'Unknown' }, { label: 'Exported by', value: previewData.exported_by || 'Unknown' }, { label: 'Fields', value: `${previewData.fields.length} field definition${previewData.fields.length !== 1 ? 's' : ''}` }, { label: 'Contracts', value: `${previewData.contracts.length} record${previewData.contracts.length !== 1 ? 's' : ''}` }, ].map(({ label, value }) => (

{label}

{value}

))}
{previewData.fields.length > 0 && (

Fields in backup:

{previewData.fields.map(f => ( {f.label} ))}
)}
)}
{selectedFile && ( )}
) }