diff --git a/src/components/ImageViewer.jsx b/src/components/ImageViewer.jsx index b5077ae..15401a0 100644 --- a/src/components/ImageViewer.jsx +++ b/src/components/ImageViewer.jsx @@ -1,9 +1,63 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { Button } from './ui/button'; import { X } from 'lucide-react'; function ImageViewer({ file, onClose }) { const imagePath = `/api/projects/${file.projectName}/files/content?path=${encodeURIComponent(file.path)}`; + const [imageUrl, setImageUrl] = useState(null); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(true); + + useEffect(() => { + let objectUrl; + const controller = new AbortController(); + + const loadImage = async () => { + try { + setLoading(true); + setError(null); + setImageUrl(null); + + const token = localStorage.getItem('auth-token'); + if (!token) { + setError('Missing authentication token'); + return; + } + + const response = await fetch(imagePath, { + headers: { + 'Authorization': `Bearer ${token}` + }, + signal: controller.signal + }); + + if (!response.ok) { + throw new Error(`Request failed with status ${response.status}`); + } + + const blob = await response.blob(); + objectUrl = URL.createObjectURL(blob); + setImageUrl(objectUrl); + } catch (err) { + if (err.name === 'AbortError') { + return; + } + console.error('Error loading image:', err); + setError('Unable to load image'); + } finally { + setLoading(false); + } + }; + + loadImage(); + + return () => { + controller.abort(); + if (objectUrl) { + URL.revokeObjectURL(objectUrl); + } + }; + }, [imagePath]); return (
@@ -23,22 +77,24 @@ function ImageViewer({ file, onClose }) {
- {file.name} { - e.target.style.display = 'none'; - e.target.nextSibling.style.display = 'block'; - }} - /> -
-

Unable to load image

-

{file.path}

-
+ {loading && ( +
+

Loading image…

+
+ )} + {!loading && imageUrl && ( + {file.name} + )} + {!loading && !imageUrl && ( +
+

{error || 'Unable to load image'}

+

{file.path}

+
+ )}
@@ -51,4 +107,4 @@ function ImageViewer({ file, onClose }) { ); } -export default ImageViewer; \ No newline at end of file +export default ImageViewer; diff --git a/src/components/Sidebar.jsx b/src/components/Sidebar.jsx index 24e5bf7..f619e7f 100644 --- a/src/components/Sidebar.jsx +++ b/src/components/Sidebar.jsx @@ -344,6 +344,48 @@ function Sidebar({ } }; + const createNewProject = async () => { + if (!newProjectPath.trim()) { + alert('Please enter a project path'); + return; + } + + setCreatingProject(true); + + try { + const response = await api.createProject(newProjectPath.trim()); + + if (response.ok) { + const result = await response.json(); + + // Save the path to recent paths before clearing + saveToRecentPaths(newProjectPath.trim()); + + setShowNewProject(false); + setNewProjectPath(''); + + // Refresh projects to show the new one + if (window.refreshProjects) { + window.refreshProjects(); + } else { + window.location.reload(); + } + } else { + const error = await response.json(); + alert(error.error || 'Failed to create project. Please try again.'); + } + } catch (error) { + console.error('Error creating project:', error); + alert('Error creating project. Please try again.'); + } finally { + setCreatingProject(false); + } + }; + + const cancelNewProject = () => { + setShowNewProject(false); + setNewProjectPath(''); + }; const loadMoreSessions = async (project) => { // Check if we can load more sessions