use reducerSplit useFileManagement hook

This commit is contained in:
2024-10-03 19:37:05 +02:00
parent fe2b9e376f
commit 7ec6823534
5 changed files with 173 additions and 130 deletions

View File

@@ -2,8 +2,8 @@ import React, { useState, useEffect } from 'react';
import { GeistProvider, CssBaseline, Page, useToasts } from '@geist-ui/core'; import { GeistProvider, CssBaseline, Page, useToasts } from '@geist-ui/core';
import Header from './components/Header'; import Header from './components/Header';
import MainContent from './components/MainContent'; import MainContent from './components/MainContent';
import useFileManagement from './hooks/useFileManagement'; import { useFileManagement } from './hooks/useFileManagement';
import { fetchUserSettings } from './services/api'; import { fetchUserSettings, lookupFileByName } from './services/api';
import './App.scss'; import './App.scss';
function App() { function App() {
@@ -37,7 +37,6 @@ function App() {
handleContentChange, handleContentChange,
handleSave, handleSave,
pullLatestChanges, pullLatestChanges,
lookupFileByName,
} = useFileManagement(settings.gitEnabled); } = useFileManagement(settings.gitEnabled);
const handleThemeChange = (newTheme) => { const handleThemeChange = (newTheme) => {

View File

@@ -0,0 +1,90 @@
import { useState, useCallback } from 'react';
import { fetchFileContent, saveFileContent } from '../services/api';
import { isImageFile } from '../utils/fileHelpers';
const DEFAULT_FILE = {
name: 'New File.md',
path: 'New File.md',
content: '# Welcome to NovaMD\n\nStart editing here!',
};
export const useFileContent = () => {
const [content, setContent] = useState(DEFAULT_FILE.content);
const [selectedFile, setSelectedFile] = useState(DEFAULT_FILE.path);
const [isNewFile, setIsNewFile] = useState(true);
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
const [error, setError] = useState(null);
const handleFileSelect = useCallback(
async (filePath) => {
if (hasUnsavedChanges) {
const confirmSwitch = window.confirm(
'You have unsaved changes. Are you sure you want to switch files?'
);
if (!confirmSwitch) return;
}
try {
if (filePath === DEFAULT_FILE.path) {
setContent(DEFAULT_FILE.content);
setSelectedFile(DEFAULT_FILE.path);
setIsNewFile(true);
} else if (!isImageFile(filePath)) {
const fileContent = await fetchFileContent(filePath);
setContent(fileContent);
setSelectedFile(filePath);
setIsNewFile(false);
} else {
setContent(''); // Set empty content for image files
setSelectedFile(filePath);
setIsNewFile(false);
}
setHasUnsavedChanges(false);
setError(null);
} catch (error) {
console.error('Failed to load file content:', error);
setError('Failed to load file content. Please try again.');
}
},
[hasUnsavedChanges]
);
const handleContentChange = useCallback((newContent) => {
setContent(newContent);
setHasUnsavedChanges(true);
}, []);
const handleSave = useCallback(async (filePath, fileContent) => {
try {
await saveFileContent(filePath, fileContent);
setIsNewFile(false);
setHasUnsavedChanges(false);
return true;
} catch (error) {
console.error('Error saving file:', error);
setError('Failed to save file. Please try again.');
return false;
}
}, []);
const createNewFile = useCallback(() => {
setContent(DEFAULT_FILE.content);
setSelectedFile(DEFAULT_FILE.path);
setIsNewFile(true);
setHasUnsavedChanges(false);
setError(null);
}, []);
return {
content,
selectedFile,
isNewFile,
hasUnsavedChanges,
error,
handleFileSelect,
handleContentChange,
handleSave,
createNewFile,
DEFAULT_FILE,
};
};

View File

@@ -0,0 +1,27 @@
import { useState, useEffect, useCallback } from 'react';
import { fetchFileList } from '../services/api';
export const useFileList = (gitEnabled) => {
const [files, setFiles] = useState([]);
const [error, setError] = useState(null);
const loadFileList = useCallback(async () => {
try {
const fileList = await fetchFileList();
if (Array.isArray(fileList)) {
setFiles(fileList);
} else {
throw new Error('File list is not an array');
}
} catch (error) {
console.error('Failed to load file list:', error);
setError('Failed to load file list. Please try again later.');
}
}, []);
useEffect(() => {
loadFileList();
}, [loadFileList, gitEnabled]);
return { files, error, loadFileList };
};

View File

@@ -1,138 +1,34 @@
import { useState, useEffect, useCallback } from 'react'; import { useFileList } from './useFileList';
import { useToasts } from '@geist-ui/core'; import { useFileContent } from './useFileContent';
import { import { useGitOperations } from './useGitOperations';
fetchFileList,
fetchFileContent,
saveFileContent,
pullChanges,
lookupFileByName,
} from '../services/api';
import { isImageFile } from '../utils/fileHelpers';
const DEFAULT_FILE = { export const useFileManagement = (gitEnabled) => {
name: 'New File.md', const { files, error: fileListError, loadFileList } = useFileList(gitEnabled);
path: 'New File.md', const {
content: '# Welcome to NovaMD\n\nStart editing here!',
};
const useFileManagement = (gitEnabled = false) => {
const [content, setContent] = useState(DEFAULT_FILE.content);
const [files, setFiles] = useState([]);
const [selectedFile, setSelectedFile] = useState(DEFAULT_FILE.path);
const [isNewFile, setIsNewFile] = useState(true);
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
const [error, setError] = useState(null);
const { setToast } = useToasts();
const loadFileList = useCallback(async () => {
try {
const fileList = await fetchFileList();
if (Array.isArray(fileList)) {
setFiles(fileList);
} else {
throw new Error('File list is not an array');
}
} catch (error) {
console.error('Failed to load file list:', error);
setError('Failed to load file list. Please try again later.');
}
}, []);
const pullLatestChanges = useCallback(async () => {
if (gitEnabled) {
try {
await pullChanges();
setToast({
text: 'Latest changes pulled successfully',
type: 'success',
});
await loadFileList(); // Reload file list after pulling changes
} catch (error) {
console.error('Failed to pull latest changes:', error);
setToast({
text: 'Failed to pull latest changes: ' + error.message,
type: 'error',
});
}
}
}, [gitEnabled, loadFileList, setToast]);
useEffect(() => {
const initializeFileSystem = async () => {
if (gitEnabled) {
await pullLatestChanges();
} else {
await loadFileList();
}
};
initializeFileSystem();
}, [gitEnabled]);
const handleFileSelect = async (filePath) => {
if (hasUnsavedChanges) {
const confirmSwitch = window.confirm(
'You have unsaved changes. Are you sure you want to switch files?'
);
if (!confirmSwitch) return;
}
try {
if (!isImageFile(filePath)) {
const fileContent = await fetchFileContent(filePath);
setContent(fileContent);
} else {
setContent(''); // Set empty content for image files
}
setSelectedFile(filePath);
setIsNewFile(false);
setHasUnsavedChanges(false);
setError(null);
} catch (error) {
console.error('Failed to load file content:', error);
setError('Failed to load file content. Please try again.');
}
};
const handleContentChange = (newContent) => {
setContent(newContent);
setHasUnsavedChanges(true);
};
const handleSave = useCallback(
async (filePath, fileContent) => {
try {
await saveFileContent(filePath, fileContent);
setToast({ text: 'File saved successfully', type: 'success' });
setIsNewFile(false);
setHasUnsavedChanges(false);
if (isNewFile) {
await loadFileList();
}
} catch (error) {
console.error('Error saving file:', error);
setToast({
text: 'Failed to save file. Please try again.',
type: 'error',
});
}
},
[setToast, isNewFile, loadFileList]
);
return {
content, content,
files,
selectedFile, selectedFile,
isNewFile, isNewFile,
hasUnsavedChanges, hasUnsavedChanges,
error, error: fileContentError,
handleFileSelect,
handleContentChange,
handleSave,
} = useFileContent();
const { pullLatestChanges, handleCommitAndPush } =
useGitOperations(gitEnabled);
return {
files,
content,
selectedFile,
isNewFile,
hasUnsavedChanges,
error: fileListError || fileContentError,
handleFileSelect, handleFileSelect,
handleContentChange, handleContentChange,
handleSave, handleSave,
pullLatestChanges, pullLatestChanges,
lookupFileByName, handleCommitAndPush,
loadFileList,
}; };
}; };
export default useFileManagement;

View File

@@ -0,0 +1,31 @@
import { useCallback } from 'react';
import { pullChanges, commitAndPush } from '../services/api';
export const useGitOperations = (gitEnabled) => {
const pullLatestChanges = useCallback(async () => {
if (!gitEnabled) return;
try {
await pullChanges();
return true;
} catch (error) {
console.error('Failed to pull latest changes:', error);
return false;
}
}, [gitEnabled]);
const handleCommitAndPush = useCallback(
async (message) => {
if (!gitEnabled) return;
try {
await commitAndPush(message);
return true;
} catch (error) {
console.error('Failed to commit and push changes:', error);
return false;
}
},
[gitEnabled]
);
return { pullLatestChanges, handleCommitAndPush };
};