phase5: workspace frontend — API hooks, useWorkspace hook, WorkspaceSwitcher, Sidebar workspace filter

This commit is contained in:
Agent Zero
2026-07-29 22:12:23 +02:00
parent bd50a85483
commit fca7191269
5 changed files with 276 additions and 2 deletions
+64
View File
@@ -0,0 +1,64 @@
import { useState, useEffect, useCallback } from 'react';
import { useMyWorkspaces, useWorkspaceContext, type WorkspaceContext } from '@/api/hooks/workspaces';
const STORAGE_KEY = 'leocrm-active-workspace';
/**
* Manages the active workspace for the current browser tab.
*
* Uses sessionStorage (per-tab, not shared across tabs) to store the active workspace ID.
* Sends X-Workspace-ID header on workspace-aware requests.
*
* Workspaces are UI/navigation context only — they never affect permissions.
*/
export function useWorkspace() {
const [activeWorkspaceId, setActiveWorkspaceId] = useState<string | null>(() => {
return sessionStorage.getItem(STORAGE_KEY);
});
const { data: myWorkspaces } = useMyWorkspaces();
const { data: context } = useWorkspaceContext(activeWorkspaceId);
// Auto-select default workspace if none selected
useEffect(() => {
if (!activeWorkspaceId && myWorkspaces?.items?.length) {
const defaultWs = myWorkspaces.items.find(w => w.is_user_default) || myWorkspaces.items[0];
if (defaultWs) {
setActiveWorkspaceId(defaultWs.id);
sessionStorage.setItem(STORAGE_KEY, defaultWs.id);
}
}
}, [activeWorkspaceId, myWorkspaces]);
// Switch workspace (per-tab)
const switchWorkspace = useCallback((workspaceId: string | null) => {
if (workspaceId) {
sessionStorage.setItem(STORAGE_KEY, workspaceId);
} else {
sessionStorage.removeItem(STORAGE_KEY);
}
setActiveWorkspaceId(workspaceId);
}, []);
// Get visible module keys from workspace context
const visibleModuleKeys: Set<string> = new Set(
context?.modules?.map(m => m.module_key) || []
);
// Check if a module is visible in the current workspace
const isModuleVisible = useCallback((moduleKey: string): boolean => {
// If no workspace context, show all (backward compatible)
if (!context?.workspace_id || !context?.modules?.length) return true;
return visibleModuleKeys.has(moduleKey);
}, [context, visibleModuleKeys]);
return {
activeWorkspaceId,
activeWorkspace: context,
myWorkspaces: myWorkspaces?.items || [],
switchWorkspace,
isModuleVisible,
visibleModuleKeys,
hasWorkspaces: (myWorkspaces?.items?.length || 0) > 0,
};
}