import React, { useState, useCallback } from 'react'; import { installLibrary } from '../../services/libraryService'; import './InstallLibrariesModal.css'; interface InstallLibrariesModalProps { isOpen: boolean; onClose: () => void; libraries: string[]; } type ItemStatus = 'pending' | 'installing' | 'done' | 'error'; interface LibItem { name: string; status: ItemStatus; error?: string; } const Spinner: React.FC<{ size?: number }> = ({ size = 16 }) => ( ); export const InstallLibrariesModal: React.FC = ({ isOpen, onClose, libraries, }) => { const [items, setItems] = useState(() => libraries.map((name) => ({ name, status: 'pending' })), ); const [running, setRunning] = useState(false); const [doneCount, setDoneCount] = useState(0); // Sync items when the libraries prop changes (new import) React.useEffect(() => { setItems(libraries.map((name) => ({ name, status: 'pending' }))); setDoneCount(0); setRunning(false); }, [libraries]); const setItemStatus = useCallback( (name: string, status: ItemStatus, error?: string) => { setItems((prev) => prev.map((it) => (it.name === name ? { ...it, status, error } : it)), ); }, [], ); const handleInstallAll = useCallback(async () => { setRunning(true); let completed = 0; for (const item of items) { if (item.status === 'done') { completed++; continue; } setItemStatus(item.name, 'installing'); try { const result = await installLibrary(item.name); if (result.success) { setItemStatus(item.name, 'done'); } else { setItemStatus(item.name, 'error', result.error || 'Install failed'); } } catch (e) { setItemStatus(item.name, 'error', e instanceof Error ? e.message : 'Install failed'); } completed++; setDoneCount(completed); } setRunning(false); }, [items, setItemStatus]); if (!isOpen) return null; const pendingCount = items.filter((i) => i.status === 'pending').length; const installedCount = items.filter((i) => i.status === 'done').length; const allDone = items.length > 0 && pendingCount === 0 && !running; return (
e.stopPropagation()}> {/* Header */}
REQUIRED LIBRARIES
{/* Subtitle */}
{running ? ( Installing {doneCount + 1} of {items.length}… ) : allDone ? ( All libraries installed successfully ) : ( This project requires {items.length} {items.length === 1 ? 'library' : 'libraries'}. Install them to compile correctly. )}
{/* Library list */}
{items.map((item) => { // For Wokwi-hosted libraries ("LibName@wokwi:hash"), show only the LibName const displayName = item.name.includes('@wokwi:') ? item.name.split('@wokwi:')[0] : item.name; const isWokwiLib = item.name.includes('@wokwi:'); return (
{displayName} {isWokwiLib && ( wokwi )} {item.status === 'pending' && pending} {item.status === 'installing' && ( installing… )} {item.status === 'done' && ( installed )} {item.status === 'error' && ( error )}
); })}
{/* Footer */}
{allDone ? ( ) : ( <> )}
); };