mirror of
https://github.com/lordmathis/lemma.git
synced 2025-11-05 15:44:21 +00:00
Migrate ModalContext and WorkspaceContext
This commit is contained in:
@@ -1,11 +1,6 @@
|
||||
import { API_BASE_URL } from '@/types/authApi';
|
||||
import { apiCall } from './api';
|
||||
import {
|
||||
DeleteWorkspaceResponse,
|
||||
isWorkspace,
|
||||
LastWorkspaceNameResponse,
|
||||
Workspace,
|
||||
} from '@/types/workspace';
|
||||
import { isWorkspace, Workspace } from '@/types/workspace';
|
||||
|
||||
/**
|
||||
* listWorkspaces fetches the list of workspaces
|
||||
@@ -97,12 +92,12 @@ export const updateWorkspace = async (
|
||||
/**
|
||||
* deleteWorkspace deletes the workspace with the given name
|
||||
* @param workspaceName - The name of the workspace to delete
|
||||
* @returns {Promise<DeleteWorkspaceResponse>} A promise that resolves to the response object
|
||||
* @returns {Promise<string>} A promise that resolves to the next workspace name to switch to
|
||||
* @throws {Error} If the API call fails or returns an invalid response
|
||||
*/
|
||||
export const deleteWorkspace = async (
|
||||
workspaceName: string
|
||||
): Promise<DeleteWorkspaceResponse> => {
|
||||
): Promise<string> => {
|
||||
const response = await apiCall(
|
||||
`${API_BASE_URL}/workspaces/${encodeURIComponent(workspaceName)}`,
|
||||
{
|
||||
@@ -113,23 +108,22 @@ export const deleteWorkspace = async (
|
||||
if (!('nextWorkspaceName' in data)) {
|
||||
throw new Error('Invalid delete workspace response received from API');
|
||||
}
|
||||
return data as DeleteWorkspaceResponse;
|
||||
return data.nextWorkspaceName as string;
|
||||
};
|
||||
|
||||
/**
|
||||
* getLastWorkspaceName fetches the last workspace name
|
||||
* @returns {Promise<LastWorkspaceNameResponse>} A promise that resolves to the last workspace name
|
||||
* @returns {Promise<string>} A promise that resolves to the last workspace name
|
||||
* @throws {Error} If the API call fails or returns an invalid response
|
||||
*/
|
||||
export const getLastWorkspaceName =
|
||||
async (): Promise<LastWorkspaceNameResponse> => {
|
||||
const response = await apiCall(`${API_BASE_URL}/workspaces/last`);
|
||||
const data = await response.json();
|
||||
if (!('lastWorkspaceName' in data)) {
|
||||
throw new Error('Invalid last workspace name response received from API');
|
||||
}
|
||||
return data as LastWorkspaceNameResponse;
|
||||
};
|
||||
export const getLastWorkspaceName = async (): Promise<string> => {
|
||||
const response = await apiCall(`${API_BASE_URL}/workspaces/last`);
|
||||
const data = await response.json();
|
||||
if (!('lastWorkspaceName' in data)) {
|
||||
throw new Error('Invalid last workspace name response received from API');
|
||||
}
|
||||
return data.lastWorkspaceName as string;
|
||||
};
|
||||
|
||||
/**
|
||||
* updateLastWorkspaceName updates the last workspace name
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import React, { createContext, useContext, useState } from 'react';
|
||||
|
||||
const ModalContext = createContext();
|
||||
|
||||
export const ModalProvider = ({ children }) => {
|
||||
const [newFileModalVisible, setNewFileModalVisible] = useState(false);
|
||||
const [deleteFileModalVisible, setDeleteFileModalVisible] = useState(false);
|
||||
const [commitMessageModalVisible, setCommitMessageModalVisible] =
|
||||
useState(false);
|
||||
const [settingsModalVisible, setSettingsModalVisible] = useState(false);
|
||||
const [switchWorkspaceModalVisible, setSwitchWorkspaceModalVisible] =
|
||||
useState(false);
|
||||
const [createWorkspaceModalVisible, setCreateWorkspaceModalVisible] =
|
||||
useState(false);
|
||||
|
||||
const value = {
|
||||
newFileModalVisible,
|
||||
setNewFileModalVisible,
|
||||
deleteFileModalVisible,
|
||||
setDeleteFileModalVisible,
|
||||
commitMessageModalVisible,
|
||||
setCommitMessageModalVisible,
|
||||
settingsModalVisible,
|
||||
setSettingsModalVisible,
|
||||
switchWorkspaceModalVisible,
|
||||
setSwitchWorkspaceModalVisible,
|
||||
createWorkspaceModalVisible,
|
||||
setCreateWorkspaceModalVisible,
|
||||
};
|
||||
|
||||
return (
|
||||
<ModalContext.Provider value={value}>{children}</ModalContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useModalContext = () => useContext(ModalContext);
|
||||
62
app/src/contexts/ModalContext.tsx
Normal file
62
app/src/contexts/ModalContext.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import React, { createContext, useContext, useState, ReactNode } from 'react';
|
||||
|
||||
interface ModalContextType {
|
||||
newFileModalVisible: boolean;
|
||||
setNewFileModalVisible: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
deleteFileModalVisible: boolean;
|
||||
setDeleteFileModalVisible: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
commitMessageModalVisible: boolean;
|
||||
setCommitMessageModalVisible: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
settingsModalVisible: boolean;
|
||||
setSettingsModalVisible: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
switchWorkspaceModalVisible: boolean;
|
||||
setSwitchWorkspaceModalVisible: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
createWorkspaceModalVisible: boolean;
|
||||
setCreateWorkspaceModalVisible: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
}
|
||||
|
||||
// Create the context with a default undefined value
|
||||
const ModalContext = createContext<ModalContextType | null>(null);
|
||||
|
||||
interface ModalProviderProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export const ModalProvider: React.FC<ModalProviderProps> = ({ children }) => {
|
||||
const [newFileModalVisible, setNewFileModalVisible] = useState(false);
|
||||
const [deleteFileModalVisible, setDeleteFileModalVisible] = useState(false);
|
||||
const [commitMessageModalVisible, setCommitMessageModalVisible] =
|
||||
useState(false);
|
||||
const [settingsModalVisible, setSettingsModalVisible] = useState(false);
|
||||
const [switchWorkspaceModalVisible, setSwitchWorkspaceModalVisible] =
|
||||
useState(false);
|
||||
const [createWorkspaceModalVisible, setCreateWorkspaceModalVisible] =
|
||||
useState(false);
|
||||
|
||||
const value: ModalContextType = {
|
||||
newFileModalVisible,
|
||||
setNewFileModalVisible,
|
||||
deleteFileModalVisible,
|
||||
setDeleteFileModalVisible,
|
||||
commitMessageModalVisible,
|
||||
setCommitMessageModalVisible,
|
||||
settingsModalVisible,
|
||||
setSettingsModalVisible,
|
||||
switchWorkspaceModalVisible,
|
||||
setSwitchWorkspaceModalVisible,
|
||||
createWorkspaceModalVisible,
|
||||
setCreateWorkspaceModalVisible,
|
||||
};
|
||||
|
||||
return (
|
||||
<ModalContext.Provider value={value}>{children}</ModalContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useModalContext = (): ModalContextType => {
|
||||
const context = useContext(ModalContext);
|
||||
if (context === null) {
|
||||
throw new Error('useModalContext must be used within a ModalProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -4,28 +4,53 @@ import React, {
|
||||
useState,
|
||||
useEffect,
|
||||
useCallback,
|
||||
ReactNode,
|
||||
} from 'react';
|
||||
import { useMantineColorScheme } from '@mantine/core';
|
||||
import { MantineColorScheme, useMantineColorScheme } from '@mantine/core';
|
||||
import { notifications } from '@mantine/notifications';
|
||||
import {
|
||||
fetchLastWorkspaceName,
|
||||
getLastWorkspaceName,
|
||||
getWorkspace,
|
||||
updateWorkspace,
|
||||
updateLastWorkspaceName,
|
||||
deleteWorkspace,
|
||||
listWorkspaces,
|
||||
} from '../api/git';
|
||||
import { DEFAULT_WORKSPACE_SETTINGS } from '../utils/constants';
|
||||
} from '@/api/workspace';
|
||||
import {
|
||||
Workspace,
|
||||
DEFAULT_WORKSPACE_SETTINGS,
|
||||
WorkspaceSettings,
|
||||
} from '@/types/workspace';
|
||||
|
||||
const WorkspaceContext = createContext();
|
||||
interface WorkspaceContextType {
|
||||
currentWorkspace: Workspace | null;
|
||||
workspaces: Workspace[];
|
||||
settings: Workspace | typeof 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 WorkspaceProvider = ({ children }) => {
|
||||
const [currentWorkspace, setCurrentWorkspace] = useState(null);
|
||||
const [workspaces, setWorkspaces] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const WorkspaceContext = createContext<WorkspaceContextType | null>(null);
|
||||
|
||||
interface WorkspaceProviderProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export const WorkspaceProvider: React.FC<WorkspaceProviderProps> = ({
|
||||
children,
|
||||
}) => {
|
||||
const [currentWorkspace, setCurrentWorkspace] = useState<Workspace | null>(
|
||||
null
|
||||
);
|
||||
const [workspaces, setWorkspaces] = useState<Workspace[]>([]);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const { colorScheme, setColorScheme } = useMantineColorScheme();
|
||||
|
||||
const loadWorkspaces = useCallback(async () => {
|
||||
const loadWorkspaces = useCallback(async (): Promise<Workspace[]> => {
|
||||
try {
|
||||
const workspaceList = await listWorkspaces();
|
||||
setWorkspaces(workspaceList);
|
||||
@@ -41,22 +66,25 @@ export const WorkspaceProvider = ({ children }) => {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const loadWorkspaceData = useCallback(async (workspaceName) => {
|
||||
try {
|
||||
const workspace = await getWorkspace(workspaceName);
|
||||
setCurrentWorkspace(workspace);
|
||||
setColorScheme(workspace.theme);
|
||||
} catch (error) {
|
||||
console.error('Failed to load workspace data:', error);
|
||||
notifications.show({
|
||||
title: 'Error',
|
||||
message: 'Failed to load workspace data',
|
||||
color: 'red',
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
const loadWorkspaceData = useCallback(
|
||||
async (workspaceName: string): Promise<void> => {
|
||||
try {
|
||||
const workspace = await getWorkspace(workspaceName);
|
||||
setCurrentWorkspace(workspace);
|
||||
setColorScheme(workspace.theme as MantineColorScheme);
|
||||
} catch (error) {
|
||||
console.error('Failed to load workspace data:', error);
|
||||
notifications.show({
|
||||
title: 'Error',
|
||||
message: 'Failed to load workspace data',
|
||||
color: 'red',
|
||||
});
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const loadFirstAvailableWorkspace = useCallback(async () => {
|
||||
const loadFirstAvailableWorkspace = useCallback(async (): Promise<void> => {
|
||||
try {
|
||||
const allWorkspaces = await listWorkspaces();
|
||||
if (allWorkspaces.length > 0) {
|
||||
@@ -75,9 +103,9 @@ export const WorkspaceProvider = ({ children }) => {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const initializeWorkspace = async () => {
|
||||
const initializeWorkspace = async (): Promise<void> => {
|
||||
try {
|
||||
const { lastWorkspaceName } = await fetchLastWorkspaceName();
|
||||
const lastWorkspaceName = await getLastWorkspaceName();
|
||||
if (lastWorkspaceName) {
|
||||
await loadWorkspaceData(lastWorkspaceName);
|
||||
} else {
|
||||
@@ -95,25 +123,28 @@ export const WorkspaceProvider = ({ children }) => {
|
||||
initializeWorkspace();
|
||||
}, []);
|
||||
|
||||
const switchWorkspace = useCallback(async (workspaceName) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
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',
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
const switchWorkspace = useCallback(
|
||||
async (workspaceName: string): Promise<void> => {
|
||||
try {
|
||||
setLoading(true);
|
||||
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',
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const deleteCurrentWorkspace = useCallback(async () => {
|
||||
const deleteCurrentWorkspace = useCallback(async (): Promise<void> => {
|
||||
if (!currentWorkspace) return;
|
||||
|
||||
try {
|
||||
@@ -129,10 +160,12 @@ export const WorkspaceProvider = ({ children }) => {
|
||||
}
|
||||
|
||||
// Delete workspace and get the next workspace ID
|
||||
const response = await deleteWorkspace(currentWorkspace.name);
|
||||
const nextWorkspaceName: string = await deleteWorkspace(
|
||||
currentWorkspace.name
|
||||
);
|
||||
|
||||
// Load the new workspace data
|
||||
await loadWorkspaceData(response.nextWorkspaceName);
|
||||
await loadWorkspaceData(nextWorkspaceName);
|
||||
|
||||
notifications.show({
|
||||
title: 'Success',
|
||||
@@ -152,7 +185,7 @@ export const WorkspaceProvider = ({ children }) => {
|
||||
}, [currentWorkspace]);
|
||||
|
||||
const updateSettings = useCallback(
|
||||
async (newSettings) => {
|
||||
async (newSettings: Partial<Workspace>): Promise<void> => {
|
||||
if (!currentWorkspace) return;
|
||||
|
||||
try {
|
||||
@@ -177,13 +210,13 @@ export const WorkspaceProvider = ({ children }) => {
|
||||
);
|
||||
|
||||
const updateColorScheme = useCallback(
|
||||
(newTheme) => {
|
||||
(newTheme: MantineColorScheme): void => {
|
||||
setColorScheme(newTheme);
|
||||
},
|
||||
[setColorScheme]
|
||||
);
|
||||
|
||||
const value = {
|
||||
const value: WorkspaceContextType = {
|
||||
currentWorkspace,
|
||||
workspaces,
|
||||
settings: currentWorkspace || DEFAULT_WORKSPACE_SETTINGS,
|
||||
@@ -202,9 +235,9 @@ export const WorkspaceProvider = ({ children }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const useWorkspace = () => {
|
||||
export const useWorkspace = (): WorkspaceContextType => {
|
||||
const context = useContext(WorkspaceContext);
|
||||
if (context === undefined) {
|
||||
if (!context) {
|
||||
throw new Error('useWorkspace must be used within a WorkspaceProvider');
|
||||
}
|
||||
return context;
|
||||
@@ -1,13 +1,5 @@
|
||||
import { Theme } from './theme';
|
||||
|
||||
export interface DeleteWorkspaceResponse {
|
||||
nextWorkspaceName: string;
|
||||
}
|
||||
|
||||
export interface LastWorkspaceNameResponse {
|
||||
lastWorkspaceName: string;
|
||||
}
|
||||
|
||||
export interface WorkspaceSettings {
|
||||
theme: Theme;
|
||||
autoSave: boolean;
|
||||
|
||||
Reference in New Issue
Block a user