diff --git a/frontend/src/components/Editor.js b/frontend/src/components/Editor.js index f1b984e..1491f8e 100644 --- a/frontend/src/components/Editor.js +++ b/frontend/src/components/Editor.js @@ -12,8 +12,6 @@ const Editor = ({ content, handleContentChange, handleSave, selectedFile }) => { const editorRef = useRef(); const viewRef = useRef(); - console.log('Editor content:', content); - useEffect(() => { const handleEditorSave = (view) => { handleSave(selectedFile, view.state.doc.toString()); @@ -72,7 +70,7 @@ const Editor = ({ content, handleContentChange, handleSave, selectedFile }) => { return () => { view.destroy(); }; - }, [selectedFile, settings.theme, handleContentChange, handleSave]); + }, [settings.theme, handleContentChange]); useEffect(() => { if (viewRef.current && content !== viewRef.current.state.doc.toString()) { diff --git a/frontend/src/components/MainContent.js b/frontend/src/components/MainContent.js index a122698..0d7b56a 100644 --- a/frontend/src/components/MainContent.js +++ b/frontend/src/components/MainContent.js @@ -1,6 +1,5 @@ -import React from 'react'; -import { useState, useCallback, useEffect } from 'react'; -import { Breadcrumbs, Dot, Grid, Tabs } from '@geist-ui/core'; +import React, { useState, useCallback, useEffect } from 'react'; +import { Breadcrumbs, Grid, Tabs, Dot } from '@geist-ui/core'; import { Code, Eye } from '@geist-ui/icons'; import FileActions from './FileActions'; @@ -19,34 +18,56 @@ import { useFileNavigation } from '../hooks/useFileNavigation'; const MainContent = () => { const [activeTab, setActiveTab] = useState('source'); const { files, loadFileList } = useFileList(); - const { content, hasUnsavedChanges, handleContentChange } = useFileContent(); + const { handleLinkClick, selectedFile, handleFileSelect } = + useFileNavigation(); + const { + content, + hasUnsavedChanges, + setHasUnsavedChanges, + handleContentChange, + } = useFileContent(selectedFile); const { handleSave, handleCreate, handleDelete } = useFileOperations(); const { handleCommitAndPush, handlePull } = useGitOperations(); - const { handleLinkClick, selectedFile, isNewFile, handleFileSelect } = - useFileNavigation(); useEffect(() => { loadFileList(); - }, []); + }, [loadFileList]); const handleTabChange = (value) => { setActiveTab(value); }; + const handleSaveFile = useCallback( + async (filePath, content) => { + const success = await handleSave(filePath, content); + if (success) { + setHasUnsavedChanges(false); + } + return success; + }, + [handleSave, setHasUnsavedChanges] + ); + const handleCreateFile = useCallback( async (fileName) => { - await handleCreate(fileName); - await loadFileList(); + const success = await handleCreate(fileName); + if (success) { + await loadFileList(); + handleFileSelect(fileName); + } }, - [handleCreate, loadFileList] + [handleCreate, loadFileList, handleFileSelect] ); const handleDeleteFile = useCallback( async (filePath) => { - await handleDelete(filePath); - await loadFileList(); + const success = await handleDelete(filePath); + if (success) { + await loadFileList(); + handleFileSelect(null); + } }, - [handleDelete, loadFileList] + [handleDelete, loadFileList, handleFileSelect] ); const renderBreadcrumbs = () => { @@ -103,7 +124,7 @@ const MainContent = () => { selectedFile={selectedFile} content={content} handleContentChange={handleContentChange} - handleSave={handleSave} + handleSave={handleSaveFile} handleLinkClick={handleLinkClick} /> diff --git a/frontend/src/hooks/useFileContent.js b/frontend/src/hooks/useFileContent.js index 53565a0..ba12b22 100644 --- a/frontend/src/hooks/useFileContent.js +++ b/frontend/src/hooks/useFileContent.js @@ -1,32 +1,47 @@ -import { useState, useCallback } from 'react'; +import { useState, useCallback, useEffect } from 'react'; import { fetchFileContent } from '../services/api'; import { isImageFile } from '../utils/fileHelpers'; import { DEFAULT_FILE } from '../utils/constants'; -export const useFileContent = () => { +export const useFileContent = (selectedFile) => { const [content, setContent] = useState(DEFAULT_FILE.content); + const [originalContent, setOriginalContent] = useState(DEFAULT_FILE.content); const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false); const loadFileContent = useCallback(async (filePath) => { try { + let newContent; if (filePath === DEFAULT_FILE.path) { - setContent(DEFAULT_FILE.content); + newContent = DEFAULT_FILE.content; } else if (!isImageFile(filePath)) { - const fileContent = await fetchFileContent(filePath); - setContent(fileContent); + newContent = await fetchFileContent(filePath); } else { - setContent(''); // Set empty content for image files + newContent = ''; // Set empty content for image files } + setContent(newContent); + setOriginalContent(newContent); setHasUnsavedChanges(false); } catch (err) { - console.error(err); + console.error('Error loading file content:', err); + setContent(''); // Set empty content on error + setOriginalContent(''); + setHasUnsavedChanges(false); } }, []); - const handleContentChange = useCallback((newContent) => { - setContent(newContent); - setHasUnsavedChanges(true); - }, []); + useEffect(() => { + if (selectedFile) { + loadFileContent(selectedFile); + } + }, [selectedFile, loadFileContent]); + + const handleContentChange = useCallback( + (newContent) => { + setContent(newContent); + setHasUnsavedChanges(newContent !== originalContent); + }, + [originalContent] + ); return { content, diff --git a/frontend/src/hooks/useFileOperations.js b/frontend/src/hooks/useFileOperations.js index f604dde..ca64b84 100644 --- a/frontend/src/hooks/useFileOperations.js +++ b/frontend/src/hooks/useFileOperations.js @@ -2,43 +2,53 @@ import { useCallback } from 'react'; import { saveFileContent, deleteFile } from '../services/api'; import { useToasts } from '@geist-ui/core'; -export const useFileOperations = (setHasUnsavedChanges) => { +export const useFileOperations = () => { const { setToast } = useToasts(); - const handleSave = useCallback(async (filePath, content) => { - try { - await saveFileContent(filePath, content); - setHasUnsavedChanges(false); - setToast({ text: 'File saved successfully', type: 'success' }); - return true; - } catch (error) { - console.error('Error saving file:', error); - return false; - } - }, []); + const handleSave = useCallback( + async (filePath, content) => { + try { + await saveFileContent(filePath, content); + setToast({ text: 'File saved successfully', type: 'success' }); + return true; + } catch (error) { + console.error('Error saving file:', error); + setToast({ text: 'Failed to save file', type: 'error' }); + return false; + } + }, + [setToast] + ); - const handleDelete = useCallback(async (filePath) => { - try { - await deleteFile(filePath); - setToast({ text: 'File deleted successfully', type: 'success' }); - return true; - } catch (error) { - setToast({ text: `Error deleting file`, type: 'error' }); - console.error('Error deleting file:', error); - return false; - } - }, []); + const handleDelete = useCallback( + async (filePath) => { + try { + await deleteFile(filePath); + setToast({ text: 'File deleted successfully', type: 'success' }); + return true; + } catch (error) { + setToast({ text: `Error deleting file`, type: 'error' }); + console.error('Error deleting file:', error); + return false; + } + }, + [setToast] + ); - const handleCreate = useCallback(async (fileName, initialContent = '') => { - try { - await saveFileContent(fileName, initialContent); - return true; - } catch (error) { - setToast({ text: `Error creating new file`, type: 'error' }); - console.error('Error creating new file:', error); - return false; - } - }, []); + const handleCreate = useCallback( + async (fileName, initialContent = '') => { + try { + await saveFileContent(fileName, initialContent); + setToast({ text: 'File created successfully', type: 'success' }); + return true; + } catch (error) { + setToast({ text: `Error creating new file`, type: 'error' }); + console.error('Error creating new file:', error); + return false; + } + }, + [setToast] + ); return { handleSave, handleDelete, handleCreate }; };