2026-07-29 22:12:23 +02:00
|
|
|
import { useState, useEffect, useCallback } from 'react';
|
|
|
|
|
import { useMyWorkspaces, useWorkspaceContext, type WorkspaceContext } from '@/api/hooks/workspaces';
|
2026-07-30 01:25:29 +02:00
|
|
|
import { useAuthStore } from '@/store/authStore';
|
2026-07-29 22:12:23 +02:00
|
|
|
|
|
|
|
|
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 => {
|
2026-07-30 01:25:29 +02:00
|
|
|
// System admins see all modules regardless of workspace
|
|
|
|
|
const user = useAuthStore.getState().user;
|
|
|
|
|
if (user?.is_system_admin) return true;
|
2026-07-30 01:53:30 +02:00
|
|
|
// While permissions are loading (is_system_admin undefined), show everything
|
|
|
|
|
if (user && user.is_system_admin === undefined) return true;
|
2026-07-30 01:25:29 +02:00
|
|
|
// If no workspace context, show all (backward compatible)
|
2026-07-29 22:12:23 +02:00
|
|
|
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,
|
|
|
|
|
};
|
|
|
|
|
}
|