mirror of
https://github.com/lordmathis/lemma.git
synced 2025-11-05 23:44:22 +00:00
245 lines
6.7 KiB
TypeScript
245 lines
6.7 KiB
TypeScript
import type {
|
|
ReactNode} from 'react';
|
|
import React, {
|
|
createContext,
|
|
useContext,
|
|
useState,
|
|
useEffect,
|
|
useCallback
|
|
} from 'react';
|
|
import type { MantineColorScheme} from '@mantine/core';
|
|
import { useMantineColorScheme } from '@mantine/core';
|
|
import { notifications } from '@mantine/notifications';
|
|
import {
|
|
getLastWorkspaceName,
|
|
getWorkspace,
|
|
updateWorkspace,
|
|
updateLastWorkspaceName,
|
|
deleteWorkspace,
|
|
listWorkspaces,
|
|
} from '@/api/workspace';
|
|
import type { Workspace} from '@/types/workspace';
|
|
import { DEFAULT_WORKSPACE_SETTINGS } from '@/types/workspace';
|
|
|
|
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>;
|
|
}
|
|
|
|
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 (): Promise<Workspace[]> => {
|
|
try {
|
|
const workspaceList = await listWorkspaces();
|
|
setWorkspaces(workspaceList);
|
|
return workspaceList;
|
|
} catch (error) {
|
|
console.error('Failed to load workspaces:', error);
|
|
notifications.show({
|
|
title: 'Error',
|
|
message: 'Failed to load workspaces list',
|
|
color: 'red',
|
|
});
|
|
return [];
|
|
}
|
|
}, []);
|
|
|
|
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 (): Promise<void> => {
|
|
try {
|
|
const allWorkspaces = await listWorkspaces();
|
|
if (allWorkspaces.length > 0) {
|
|
const firstWorkspace = allWorkspaces[0];
|
|
if (!firstWorkspace) throw new Error('No workspaces available');
|
|
await updateLastWorkspaceName(firstWorkspace.name);
|
|
await loadWorkspaceData(firstWorkspace.name);
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to load first available workspace:', error);
|
|
notifications.show({
|
|
title: 'Error',
|
|
message: 'Failed to load workspace',
|
|
color: 'red',
|
|
});
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
const initializeWorkspace = async (): Promise<void> => {
|
|
try {
|
|
const lastWorkspaceName = await getLastWorkspaceName();
|
|
if (lastWorkspaceName) {
|
|
await loadWorkspaceData(lastWorkspaceName);
|
|
} else {
|
|
await loadFirstAvailableWorkspace();
|
|
}
|
|
await loadWorkspaces();
|
|
} catch (error) {
|
|
console.error('Failed to initialize workspace:', error);
|
|
await loadFirstAvailableWorkspace();
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
initializeWorkspace();
|
|
}, []);
|
|
|
|
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 (): 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]);
|
|
|
|
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);
|
|
setColorScheme(response.theme);
|
|
await loadWorkspaces();
|
|
} catch (error) {
|
|
console.error('Failed to save settings:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
[currentWorkspace, setColorScheme]
|
|
);
|
|
|
|
const updateColorScheme = useCallback(
|
|
(newTheme: MantineColorScheme): void => {
|
|
setColorScheme(newTheme);
|
|
},
|
|
[setColorScheme]
|
|
);
|
|
|
|
const value: WorkspaceContextType = {
|
|
currentWorkspace,
|
|
workspaces,
|
|
settings: currentWorkspace || DEFAULT_WORKSPACE_SETTINGS,
|
|
updateSettings,
|
|
loading,
|
|
colorScheme,
|
|
updateColorScheme,
|
|
switchWorkspace,
|
|
deleteCurrentWorkspace,
|
|
};
|
|
|
|
return (
|
|
<WorkspaceContext.Provider value={value}>
|
|
{children}
|
|
</WorkspaceContext.Provider>
|
|
);
|
|
};
|
|
|
|
export const useWorkspace = (): WorkspaceContextType => {
|
|
const context = useContext(WorkspaceContext);
|
|
if (!context) {
|
|
throw new Error('useWorkspace must be used within a WorkspaceProvider');
|
|
}
|
|
return context;
|
|
};
|