import React, { useEffect, useState } from 'react'; import { Layout } from '../components/Layout'; import { useNavigate } from 'react-router-dom'; import * as api from '../api'; import type { Collection } from '../types'; import { Database, FileJson, Upload, Moon, Sun, Info, HardDrive } from 'lucide-react'; import { ConfirmModal } from '../components/ConfirmModal'; import { importDrawings } from '../utils/importUtils'; import { useTheme } from '../context/ThemeContext'; export const Settings: React.FC = () => { const [collections, setCollections] = useState([]); const navigate = useNavigate(); const { theme, toggleTheme } = useTheme(); // Import state const [importConfirmation, setImportConfirmation] = useState<{ isOpen: boolean; file: File | null }>({ isOpen: false, file: null }); const [importError, setImportError] = useState<{ isOpen: boolean; message: string }>({ isOpen: false, message: '' }); const [importSuccess, setImportSuccess] = useState(false); const appVersion = import.meta.env.VITE_APP_VERSION || 'Unknown version'; const buildLabel = import.meta.env.VITE_APP_BUILD_LABEL; useEffect(() => { const fetchCollections = async () => { try { const data = await api.getCollections(); setCollections(data); } catch (err) { console.error('Failed to fetch collections:', err); } }; fetchCollections(); }, []); const handleCreateCollection = async (name: string) => { await api.createCollection(name); const newCollections = await api.getCollections(); setCollections(newCollections); }; const handleEditCollection = async (id: string, name: string) => { setCollections(prev => prev.map(c => c.id === id ? { ...c, name } : c)); await api.updateCollection(id, name); }; const handleDeleteCollection = async (id: string) => { setCollections(prev => prev.filter(c => c.id !== id)); await api.deleteCollection(id); }; const handleSelectCollection = (id: string | null | undefined) => { // Navigate to dashboard with selected collection if (id === undefined) navigate('/'); else if (id === null) navigate('/collections?id=unorganized'); else navigate(`/collections?id=${id}`); }; return (

Settings

{/* Theme Toggle */} {/* Export SQLite (.sqlite) */} {/* Export SQLite (.db) */} {/* Export JSON */} {/* Import Data */}
{ const files = Array.from(e.target.files || []); if (files.length === 0) return; // Handle Database Import (.sqlite or .db) const databaseFile = files.find(f => f.name.endsWith('.sqlite') || f.name.endsWith('.db')); if (databaseFile) { if (files.length > 1) { setImportError({ isOpen: true, message: 'Please import database files separately from other files.' }); e.target.value = ''; return; } const formData = new FormData(); formData.append('db', databaseFile); try { const res = await fetch(`${api.API_URL}/import/sqlite/verify`, { method: 'POST', body: formData, }); if (!res.ok) { const errorData = await res.json(); setImportError({ isOpen: true, message: errorData.error || 'Invalid database file.' }); e.target.value = ''; return; } setImportConfirmation({ isOpen: true, file: databaseFile }); } catch (err) { console.error('Verification failed:', err); setImportError({ isOpen: true, message: 'Failed to verify database file.' }); } e.target.value = ''; return; } // Handle Bulk Drawing Import const drawingFiles = files.filter(f => f.name.endsWith('.json') || f.name.endsWith('.excalidraw')); if (drawingFiles.length === 0) { setImportError({ isOpen: true, message: 'No supported files found.' }); e.target.value = ''; return; } const result = await importDrawings(drawingFiles, null, () => { }); if (result.failed > 0) { setImportError({ isOpen: true, message: `Import complete with errors.\nSuccess: ${result.success}\nFailed: ${result.failed}\nErrors:\n${result.errors.join('\n')}` }); } else { setImportSuccess(true); } e.target.value = ''; }} />
{/* Version Info */}

Version Info

{appVersion} {buildLabel && ( {buildLabel} )}
{/* Modals */} { if (!importConfirmation.file) return; const formData = new FormData(); formData.append('db', importConfirmation.file); try { const res = await fetch(`${api.API_URL}/import/sqlite`, { method: 'POST', body: formData, }); if (!res.ok) { const errorData = await res.json(); throw new Error(errorData.error || 'Import failed'); } setImportConfirmation({ isOpen: false, file: null }); setImportSuccess(true); } catch (err: any) { console.error(err); setImportError({ isOpen: true, message: `Failed to import database: ${err.message}` }); setImportConfirmation({ isOpen: false, file: null }); } }} onCancel={() => setImportConfirmation({ isOpen: false, file: null })} /> setImportError({ isOpen: false, message: '' })} onCancel={() => setImportError({ isOpen: false, message: '' })} /> setImportSuccess(false)} onCancel={() => setImportSuccess(false)} />
); };