Refactor workspace context usage to improve structure and introduce ThemeContext

This commit is contained in:
2025-05-25 12:11:03 +02:00
parent 6cf118280a
commit a724bc44e9
20 changed files with 381 additions and 252 deletions

View File

@@ -1,6 +1,6 @@
import { useState, useCallback, useEffect } from 'react';
import { isImageFile } from '../utils/fileHelpers';
import { useWorkspace } from '../contexts/WorkspaceContext';
import { useWorkspaceData } from '../contexts/WorkspaceDataContext';
import { getFileContent } from '@/api/file';
import { DEFAULT_FILE } from '@/types/models';
@@ -16,7 +16,7 @@ interface UseFileContentResult {
export const useFileContent = (
selectedFile: string | null
): UseFileContentResult => {
const { currentWorkspace } = useWorkspace();
const { currentWorkspace } = useWorkspaceData();
const [content, setContent] = useState<string>(DEFAULT_FILE.content);
const [originalContent, setOriginalContent] = useState<string>(
DEFAULT_FILE.content

View File

@@ -1,6 +1,6 @@
import { useState, useCallback } from 'react';
import { listFiles } from '../api/file';
import { useWorkspace } from '../contexts/WorkspaceContext';
import { useWorkspaceData } from '../contexts/WorkspaceDataContext';
import type { FileNode } from '@/types/models';
interface UseFileListResult {
@@ -10,7 +10,7 @@ interface UseFileListResult {
export const useFileList = (): UseFileListResult => {
const [files, setFiles] = useState<FileNode[]>([]);
const { currentWorkspace, loading: workspaceLoading } = useWorkspace();
const { currentWorkspace, loading: workspaceLoading } = useWorkspaceData();
const loadFileList = useCallback(async (): Promise<void> => {
if (!currentWorkspace || workspaceLoading) return;

View File

@@ -1,5 +1,5 @@
import { useState, useCallback, useEffect } from 'react';
import { useWorkspace } from '../contexts/WorkspaceContext';
import { useWorkspaceData } from '../contexts/WorkspaceDataContext';
import { useLastOpenedFile } from './useLastOpenedFile';
import { DEFAULT_FILE } from '@/types/models';
@@ -12,7 +12,7 @@ interface UseFileNavigationResult {
export const useFileNavigation = (): UseFileNavigationResult => {
const [selectedFile, setSelectedFile] = useState<string>(DEFAULT_FILE.path);
const [isNewFile, setIsNewFile] = useState<boolean>(true);
const { currentWorkspace } = useWorkspace();
const { currentWorkspace } = useWorkspaceData();
const { loadLastOpenedFile, saveLastOpenedFile } = useLastOpenedFile();
const handleFileSelect = useCallback(

View File

@@ -1,7 +1,7 @@
import { useCallback } from 'react';
import { notifications } from '@mantine/notifications';
import { saveFile, deleteFile } from '../api/file';
import { useWorkspace } from '../contexts/WorkspaceContext';
import { useWorkspaceData } from '../contexts/WorkspaceDataContext';
import { useGitOperations } from './useGitOperations';
import { FileAction } from '@/types/models';
@@ -12,7 +12,7 @@ interface UseFileOperationsResult {
}
export const useFileOperations = (): UseFileOperationsResult => {
const { currentWorkspace, settings } = useWorkspace();
const { currentWorkspace, settings } = useWorkspaceData();
const { handleCommitAndPush } = useGitOperations();
const autoCommit = useCallback(

View File

@@ -1,7 +1,7 @@
import { useCallback } from 'react';
import { notifications } from '@mantine/notifications';
import { pullChanges, commitAndPush } from '../api/git';
import { useWorkspace } from '../contexts/WorkspaceContext';
import { useWorkspaceData } from '../contexts/WorkspaceDataContext';
import type { CommitHash } from '@/types/models';
interface UseGitOperationsResult {
@@ -10,7 +10,7 @@ interface UseGitOperationsResult {
}
export const useGitOperations = (): UseGitOperationsResult => {
const { currentWorkspace, settings } = useWorkspace();
const { currentWorkspace, settings } = useWorkspaceData();
const handlePull = useCallback(async (): Promise<boolean> => {
if (!currentWorkspace || !settings.gitEnabled) return false;

View File

@@ -1,6 +1,6 @@
import { useCallback } from 'react';
import { getLastOpenedFile, updateLastOpenedFile } from '../api/file';
import { useWorkspace } from '../contexts/WorkspaceContext';
import { useWorkspaceData } from '../contexts/WorkspaceDataContext';
interface UseLastOpenedFileResult {
loadLastOpenedFile: () => Promise<string | null>;
@@ -8,7 +8,7 @@ interface UseLastOpenedFileResult {
}
export const useLastOpenedFile = (): UseLastOpenedFileResult => {
const { currentWorkspace } = useWorkspace();
const { currentWorkspace } = useWorkspaceData();
const loadLastOpenedFile = useCallback(async (): Promise<string | null> => {
if (!currentWorkspace) return null;

View File

@@ -0,0 +1,39 @@
import { useWorkspaceData } from '../contexts/WorkspaceDataContext';
import { useTheme } from '../contexts/ThemeContext';
import { useWorkspaceOperations } from './useWorkspaceOperations';
import type { Workspace } from '@/types/models';
import type { MantineColorScheme } from '@mantine/core';
interface UseWorkspaceResult {
currentWorkspace: Workspace | null;
workspaces: Workspace[];
settings:
| Workspace
| typeof import('@/types/models').DEFAULT_WORKSPACE_SETTINGS;
updateSettings: (newSettings: Partial<Workspace>) => Promise<void>;
loading: boolean;
colorScheme: MantineColorScheme;
updateColorScheme: (newTheme: MantineColorScheme) => void;
switchWorkspace: (workspaceName: string) => Promise<void>;
deleteCurrentWorkspace: () => Promise<void>;
}
export const useWorkspace = (): UseWorkspaceResult => {
const { currentWorkspace, workspaces, settings, loading } =
useWorkspaceData();
const { colorScheme, updateColorScheme } = useTheme();
const { switchWorkspace, deleteCurrentWorkspace, updateSettings } =
useWorkspaceOperations();
return {
currentWorkspace,
workspaces,
settings,
updateSettings,
loading,
colorScheme,
updateColorScheme,
switchWorkspace,
deleteCurrentWorkspace,
};
};

View File

@@ -0,0 +1,117 @@
import { useCallback } from 'react';
import { notifications } from '@mantine/notifications';
import { useWorkspaceData } from '../contexts/WorkspaceDataContext';
import {
updateLastWorkspaceName,
updateWorkspace,
deleteWorkspace,
} from '@/api/workspace';
import { useTheme } from '../contexts/ThemeContext';
import type { Workspace } from '@/types/models';
interface UseWorkspaceOperationsResult {
switchWorkspace: (workspaceName: string) => Promise<void>;
deleteCurrentWorkspace: () => Promise<void>;
updateSettings: (newSettings: Partial<Workspace>) => Promise<void>;
}
export const useWorkspaceOperations = (): UseWorkspaceOperationsResult => {
const {
currentWorkspace,
loadWorkspaceData,
loadWorkspaces,
setCurrentWorkspace,
} = useWorkspaceData();
const { updateColorScheme } = useTheme();
const switchWorkspace = useCallback(
async (workspaceName: string): Promise<void> => {
try {
await updateLastWorkspaceName(workspaceName);
await loadWorkspaceData(workspaceName);
await loadWorkspaces();
} catch (error) {
console.error('Failed to switch workspace:', error);
notifications.show({
title: 'Error',
message: 'Failed to switch workspace',
color: 'red',
});
}
},
[loadWorkspaceData, loadWorkspaces]
);
const deleteCurrentWorkspace = useCallback(async (): Promise<void> => {
if (!currentWorkspace) return;
try {
const allWorkspaces = await loadWorkspaces();
if (allWorkspaces.length <= 1) {
notifications.show({
title: 'Error',
message:
'Cannot delete the last workspace. At least one workspace must exist.',
color: 'red',
});
return;
}
// Delete workspace and get the next workspace ID
const nextWorkspaceName: string = await deleteWorkspace(
currentWorkspace.name
);
// Load the new workspace data
await loadWorkspaceData(nextWorkspaceName);
notifications.show({
title: 'Success',
message: 'Workspace deleted successfully',
color: 'green',
});
await loadWorkspaces();
} catch (error) {
console.error('Failed to delete workspace:', error);
notifications.show({
title: 'Error',
message: 'Failed to delete workspace',
color: 'red',
});
}
}, [currentWorkspace, loadWorkspaceData, loadWorkspaces]);
const updateSettings = useCallback(
async (newSettings: Partial<Workspace>): Promise<void> => {
if (!currentWorkspace) return;
try {
const updatedWorkspace = {
...currentWorkspace,
...newSettings,
};
const response = await updateWorkspace(
currentWorkspace.name,
updatedWorkspace
);
setCurrentWorkspace(response);
if (newSettings.theme) {
updateColorScheme(response.theme);
}
await loadWorkspaces();
} catch (error) {
console.error('Failed to save settings:', error);
throw error;
}
},
[currentWorkspace, loadWorkspaces, updateColorScheme, setCurrentWorkspace]
);
return {
switchWorkspace,
deleteCurrentWorkspace,
updateSettings,
};
};