From 4178ccdd5ee33df3044132eeed298f1a92dae781 Mon Sep 17 00:00:00 2001 From: Haileyesus Date: Mon, 23 Feb 2026 09:35:59 +0300 Subject: [PATCH] fix(code-editor): stabilize document loading deps and replace blocking save alerts The code editor document hook was reloading more often than necessary because `useEffect` depended on the full `file` object (and `projectPath`, which was not used in the effect body). Save flow also emitted verbose production debug logs and used a blocking `alert()` for errors. Changes: - Refactored `useCodeEditorDocument` to derive stable file primitives: `fileProjectName`, `filePath`, `fileName`, `fileDiffNewString`, `fileDiffOldString`. - Updated `loadFileContent` to use those stable fields while preserving existing diff-first loading logic (`file.diffInfo`, `new_string`, `old_string`). - Replaced the effect dependency array with only stable primitive values used by the effect and removed `projectPath` from dependencies. - Removed debug `console.log` calls in `handleSave`: - "Saving file:" - "Save response:" - "Save successful:" - Kept error logging via `console.error` for failure diagnostics. - Replaced blocking `alert()` on save failure with non-blocking UI feedback: - Added local `saveError` state in the hook. - Set `saveError` from `getErrorMessage(error)` in the save catch path. - Exposed `saveError` to `CodeEditor` and rendered an inline error banner. - Preserved save lifecycle behavior: - `setSaving(false)` still runs in `finally`. - `setSaveSuccess(true)` and 2s timeout reset behavior remain unchanged. --- .../hooks/useCodeEditorDocument.ts | 40 +++++++++---------- .../code-editor/view/CodeEditor.tsx | 7 ++++ 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/components/code-editor/hooks/useCodeEditorDocument.ts b/src/components/code-editor/hooks/useCodeEditorDocument.ts index f707f43..3303601 100644 --- a/src/components/code-editor/hooks/useCodeEditorDocument.ts +++ b/src/components/code-editor/hooks/useCodeEditorDocument.ts @@ -15,11 +15,17 @@ const getErrorMessage = (error: unknown) => { return String(error); }; -export const useCodeEditorDocument = ({ file, projectPath }: UseCodeEditorDocumentParams) => { +export const useCodeEditorDocument = ({ file }: UseCodeEditorDocumentParams) => { const [content, setContent] = useState(''); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [saveSuccess, setSaveSuccess] = useState(false); + const [saveError, setSaveError] = useState(null); + const fileProjectName = file.projectName; + const filePath = file.path; + const fileName = file.name; + const fileDiffNewString = file.diffInfo?.new_string; + const fileDiffOldString = file.diffInfo?.old_string; useEffect(() => { const loadFileContent = async () => { @@ -27,13 +33,13 @@ export const useCodeEditorDocument = ({ file, projectPath }: UseCodeEditorDocume setLoading(true); // Diff payload may already include full old/new snapshots, so avoid disk read. - if (file.diffInfo && file.diffInfo.new_string !== undefined && file.diffInfo.old_string !== undefined) { - setContent(file.diffInfo.new_string); + if (file.diffInfo && fileDiffNewString !== undefined && fileDiffOldString !== undefined) { + setContent(fileDiffNewString); setLoading(false); return; } - const response = await api.readFile(file.projectName, file.path); + const response = await api.readFile(fileProjectName, filePath); if (!response.ok) { throw new Error(`Failed to load file: ${response.status} ${response.statusText}`); } @@ -43,31 +49,21 @@ export const useCodeEditorDocument = ({ file, projectPath }: UseCodeEditorDocume } catch (error) { const message = getErrorMessage(error); console.error('Error loading file:', error); - setContent(`// Error loading file: ${message}\n// File: ${file.name}\n// Path: ${file.path}`); + setContent(`// Error loading file: ${message}\n// File: ${fileName}\n// Path: ${filePath}`); } finally { setLoading(false); } }; loadFileContent(); - }, [file, projectPath]); + }, [fileDiffNewString, fileDiffOldString, fileName, filePath, fileProjectName]); const handleSave = useCallback(async () => { setSaving(true); + setSaveError(null); try { - console.log('Saving file:', { - projectName: file.projectName, - path: file.path, - contentLength: content?.length, - }); - - const response = await api.saveFile(file.projectName, file.path, content); - console.log('Save response:', { - status: response.status, - ok: response.ok, - contentType: response.headers.get('content-type'), - }); + const response = await api.saveFile(fileProjectName, filePath, content); if (!response.ok) { const contentType = response.headers.get('content-type'); @@ -81,19 +77,18 @@ export const useCodeEditorDocument = ({ file, projectPath }: UseCodeEditorDocume throw new Error(`Save failed: ${response.status} ${response.statusText}`); } - const result = await response.json(); - console.log('Save successful:', result); + await response.json(); setSaveSuccess(true); setTimeout(() => setSaveSuccess(false), 2000); } catch (error) { const message = getErrorMessage(error); console.error('Error saving file:', error); - alert(`Error saving file: ${message}`); + setSaveError(message); } finally { setSaving(false); } - }, [content, file.path, file.projectName]); + }, [content, filePath, fileProjectName]); const handleDownload = useCallback(() => { const blob = new Blob([content], { type: 'text/plain' }); @@ -116,6 +111,7 @@ export const useCodeEditorDocument = ({ file, projectPath }: UseCodeEditorDocume loading, saving, saveSuccess, + saveError, handleSave, handleDownload, }; diff --git a/src/components/code-editor/view/CodeEditor.tsx b/src/components/code-editor/view/CodeEditor.tsx index 28243f0..c1f77f8 100644 --- a/src/components/code-editor/view/CodeEditor.tsx +++ b/src/components/code-editor/view/CodeEditor.tsx @@ -53,6 +53,7 @@ export default function CodeEditor({ loading, saving, saveSuccess, + saveError, handleSave, handleDownload, } = useCodeEditorDocument({ @@ -201,6 +202,12 @@ export default function CodeEditor({ }} /> + {saveError && ( +
+ {saveError} +
+ )} +