import { useState, useEffect } from 'react'; import { ArrowLeft, Trash2, RefreshCw, Eraser, FileText, Settings, Database, Folder, AlertTriangle } from 'lucide-react'; import { API } from '../../api/client'; import type { AppInfo, AppDetails } from '../../api/client'; import { GlassCard } from '../ui/GlassCard'; import { GlassButton } from '../ui/GlassButton'; import { useToast } from '../ui/Toast'; interface Props { app: AppInfo; onBack: () => void; onUninstall: () => void; } export function AppDetailsView({ app, onBack, onUninstall }: Props) { const [details, setDetails] = useState(null); const [loading, setLoading] = useState(true); const [selectedFiles, setSelectedFiles] = useState>(new Set()); const [processing, setProcessing] = useState(false); const toast = useToast(); useEffect(() => { loadDetails(); }, [app.path]); const loadDetails = async () => { try { setLoading(true); const data = await API.getAppDetails(app.path, app.bundleID); setDetails(data); // Select all by default const allFiles = new Set(); allFiles.add(data.path); // Main app bundle data.associated.forEach(f => allFiles.add(f.path)); setSelectedFiles(allFiles); } catch (error) { console.error(error); toast.addToast({ type: 'error', title: 'Error', message: 'Failed to load app details' }); } finally { setLoading(false); } }; const formatSize = (bytes: number) => { const units = ['B', 'KB', 'MB', 'GB']; let size = bytes; let unitIndex = 0; while (size >= 1024 && unitIndex < units.length - 1) { size /= 1024; unitIndex++; } return `${size.toFixed(1)} ${units[unitIndex]}`; }; const toggleFile = (path: string) => { const newSet = new Set(selectedFiles); if (newSet.has(path)) { newSet.delete(path); } else { newSet.add(path); } setSelectedFiles(newSet); }; const getIconForType = (type: string) => { switch (type) { case 'config': return ; case 'cache': return ; case 'log': return ; case 'registry': return ; default: return ; } }; const handleAction = async (action: 'uninstall' | 'reset' | 'cache') => { if (!details) return; // Special handling for Uninstall with official uninstaller if (action === 'uninstall' && details.uninstallString) { const confirmed = await toast.confirm( `Run Uninstaller?`, `This will launch the official uninstaller for ${details.name}.` ); if (!confirmed) return; try { setProcessing(true); await API.uninstallApp(details.uninstallString); toast.addToast({ type: 'success', title: 'Success', message: 'Uninstaller launched' }); // We don't automatically close the view or reload apps because the uninstaller is external // But we can go back onBack(); } catch (error) { console.error(error); toast.addToast({ type: 'error', title: 'Error', message: 'Failed to launch uninstaller' }); } finally { setProcessing(false); } return; } let filesToDelete: string[] = []; if (action === 'uninstall') { filesToDelete = Array.from(selectedFiles); } else if (action === 'reset') { // Reset: Config + Data only, keep App filesToDelete = details.associated .filter(f => f.type === 'config' || f.type === 'data') .map(f => f.path); } else if (action === 'cache') { // Cache: Caches + Logs filesToDelete = details.associated .filter(f => f.type === 'cache' || f.type === 'log') .map(f => f.path); } if (filesToDelete.length === 0) { toast.addToast({ type: 'info', title: 'Info', message: 'No files selected for this action' }); return; } // Confirmation (Simple browser confirm for now, better UI later) const confirmed = await toast.confirm( `Delete ${filesToDelete.length} items?`, 'This cannot be undone.' ); if (!confirmed) return; try { setProcessing(true); await API.deleteAppFiles(filesToDelete); toast.addToast({ type: 'success', title: 'Success', message: 'Cleaned up successfully' }); if (action === 'uninstall') { onUninstall(); } else { loadDetails(); // Reload to show remaining files } } catch (error) { console.error(error); toast.addToast({ type: 'error', title: 'Error', message: 'Failed to delete files' }); } finally { setProcessing(false); } }; if (loading || !details) { return (

Analyzing application structure...

); } const totalSelectedSize = Array.from(selectedFiles).reduce((acc, path) => { if (path === details.path) return acc + details.size; const assoc = details.associated.find(f => f.path === path); return acc + (assoc ? assoc.size : 0); }, 0); return (

{details.name}

{details.bundleID}

{/* File List */}
Application Bundle & Data {formatSize(totalSelectedSize)} selected
{/* Main App */}
toggleFile(details.path)} >
{selectedFiles.has(details.path) && }
Application Bundle
{details.path}
{formatSize(details.size)}
{/* Associated Files */} {details.associated.map((file) => (
toggleFile(file.path)} >
{selectedFiles.has(file.path) && }
{getIconForType(file.type)}
{file.type}
{file.path}
{formatSize(file.size)}
))}
{/* Actions */}

Cleanup Actions

handleAction('uninstall')} disabled={processing} >
Uninstall Remove {selectedFiles.size} selected items

Deleted files cannot be recovered. Ensure you have backups of important data before uninstalling applications.

); } function PackageIcon({ className }: { className?: string }) { return ( ) }