import { create } from 'zustand'; import { SystemRoleId, SYSTEM_ROLES } from '../permissions/types'; import { CapabilityId } from '../capabilities/types'; import { BUSINESS_PROFILES } from '../profiles/profiles'; import { BusinessProfile } from '../profiles/types'; import { setActiveGlobalTenantId, getActiveGlobalTenantId } from '../../services/contracts/context'; export interface SessionState { activeTenantId: string; activeOrgId: string; currentUserId: string; currentRoleId: SystemRoleId; currentProfileId: string; activeLocation: string; capabilities: Record; // Actions setActiveTenantId: (tenantId: string) => void; setActiveOrgId: (orgId: string) => void; setCurrentUserId: (userId: string) => void; setCurrentRoleId: (roleId: SystemRoleId) => void; setCurrentProfileId: (profileId: string) => void; setActiveLocation: (location: string) => void; setCapabilities: (capabilities: Record) => void; toggleCapability: (id: CapabilityId) => void; resetCapabilitiesToProfile: () => void; resetSession: () => void; // RBAC & Permission helpers (Strict deny-by-default) hasModulePermission: (moduleId: string) => boolean; getActiveProfile: () => BusinessProfile; getActiveCapabilities: () => Record; } const DEFAULT_PROFILE_ID = 'restaurant_hall_delivery'; const DEFAULT_ROLE_ID: SystemRoleId = 'owner'; const DEFAULT_TENANT_ID = 'tenant_main'; const DEFAULT_ORG_ID = 'org_main'; const DEFAULT_USER_ID = 'user_admin'; function getInitialProfileId(): string { if (typeof window !== 'undefined') { const saved = localStorage.getItem('krona_profile_id'); if (saved && BUSINESS_PROFILES[saved]) return saved; } return DEFAULT_PROFILE_ID; } function getInitialRoleId(): SystemRoleId { if (typeof window !== 'undefined') { const saved = localStorage.getItem('krona_role_id') as SystemRoleId; if (saved && SYSTEM_ROLES[saved]) return saved; } return DEFAULT_ROLE_ID; } function getInitialTenantId(): string { if (typeof window !== 'undefined') { const saved = localStorage.getItem('krona_tenant_id') || localStorage.getItem('krona_active_tenant_id'); if (saved) return saved; } return getActiveGlobalTenantId() || DEFAULT_TENANT_ID; } function getInitialOrgId(): string { if (typeof window !== 'undefined') { const saved = localStorage.getItem('krona_org_id') || localStorage.getItem('krona_active_org_id'); if (saved) return saved; } return DEFAULT_ORG_ID; } function getInitialUserId(): string { if (typeof window !== 'undefined') { const saved = localStorage.getItem('krona_user_id') || localStorage.getItem('krona_current_user_id'); if (saved) return saved; } return DEFAULT_USER_ID; } function getInitialLocation(profileId: string): string { if (typeof window !== 'undefined') { const saved = localStorage.getItem('krona_location') || localStorage.getItem('krona_active_location'); if (saved) return saved; } const prof = BUSINESS_PROFILES[profileId] || BUSINESS_PROFILES[DEFAULT_PROFILE_ID]; return prof.locations[0] || 'Горский 1/1'; } function getInitialCapabilities(profileId: string): Record { const prof = BUSINESS_PROFILES[profileId] || BUSINESS_PROFILES[DEFAULT_PROFILE_ID]; return { ...prof.capabilities }; } export const useSessionStore = create((set, get) => { const initialProfileId = getInitialProfileId(); const initialTenantId = getInitialTenantId(); // Sync global tenant id on startup setActiveGlobalTenantId(initialTenantId); return { activeTenantId: initialTenantId, activeOrgId: getInitialOrgId(), currentUserId: getInitialUserId(), currentRoleId: getInitialRoleId(), currentProfileId: initialProfileId, activeLocation: getInitialLocation(initialProfileId), capabilities: getInitialCapabilities(initialProfileId), setActiveTenantId: (activeTenantId: string) => { if (typeof window !== 'undefined') { localStorage.setItem('krona_tenant_id', activeTenantId); localStorage.setItem('krona_active_tenant_id', activeTenantId); } setActiveGlobalTenantId(activeTenantId); set({ activeTenantId }); }, setActiveOrgId: (activeOrgId: string) => { if (typeof window !== 'undefined') { localStorage.setItem('krona_org_id', activeOrgId); localStorage.setItem('krona_active_org_id', activeOrgId); } set({ activeOrgId }); }, setCurrentUserId: (currentUserId: string) => { if (typeof window !== 'undefined') { localStorage.setItem('krona_user_id', currentUserId); localStorage.setItem('krona_current_user_id', currentUserId); } set({ currentUserId }); }, setCurrentRoleId: (currentRoleId: SystemRoleId) => { if (typeof window !== 'undefined') { localStorage.setItem('krona_role_id', currentRoleId); } set({ currentRoleId }); }, setCurrentProfileId: (currentProfileId: string) => { if (typeof window !== 'undefined') { localStorage.setItem('krona_profile_id', currentProfileId); } const profile = BUSINESS_PROFILES[currentProfileId] || BUSINESS_PROFILES[DEFAULT_PROFILE_ID]; const newLoc = profile.locations[0] || 'Главная точка'; if (typeof window !== 'undefined') { localStorage.setItem('krona_location', newLoc); } set({ currentProfileId, capabilities: { ...profile.capabilities }, activeLocation: newLoc, }); }, setActiveLocation: (activeLocation: string) => { if (typeof window !== 'undefined') { localStorage.setItem('krona_location', activeLocation); localStorage.setItem('krona_active_location', activeLocation); } set({ activeLocation }); }, setCapabilities: (capabilities: Record) => { set({ capabilities }); }, toggleCapability: (id: CapabilityId) => { set((state) => ({ capabilities: { ...state.capabilities, [id]: !state.capabilities[id], }, })); }, resetCapabilitiesToProfile: () => { const state = get(); const profile = BUSINESS_PROFILES[state.currentProfileId] || BUSINESS_PROFILES[DEFAULT_PROFILE_ID]; set({ capabilities: { ...profile.capabilities } }); }, resetSession: () => { const defaultProf = BUSINESS_PROFILES[DEFAULT_PROFILE_ID]; setActiveGlobalTenantId(DEFAULT_TENANT_ID); if (typeof window !== 'undefined') { localStorage.removeItem('krona_tenant_id'); localStorage.removeItem('krona_active_tenant_id'); localStorage.removeItem('krona_org_id'); localStorage.removeItem('krona_active_org_id'); localStorage.removeItem('krona_user_id'); localStorage.removeItem('krona_current_user_id'); localStorage.removeItem('krona_role_id'); localStorage.removeItem('krona_profile_id'); localStorage.removeItem('krona_location'); } set({ activeTenantId: DEFAULT_TENANT_ID, activeOrgId: DEFAULT_ORG_ID, currentUserId: DEFAULT_USER_ID, currentRoleId: DEFAULT_ROLE_ID, currentProfileId: DEFAULT_PROFILE_ID, activeLocation: defaultProf.locations[0] || 'Горский 1/1', capabilities: { ...defaultProf.capabilities }, }); }, // Strict deny-by-default RBAC check hasModulePermission: (moduleId: string) => { const state = get(); const role = SYSTEM_ROLES[state.currentRoleId]; if (!role) return false; // Super roles or full wildcard if (role.id === 'owner' || role.id === 'administrator' || role.allowedModules.includes('*')) { return true; } return role.allowedModules.includes(moduleId); }, getActiveProfile: () => { const state = get(); return BUSINESS_PROFILES[state.currentProfileId] || BUSINESS_PROFILES[DEFAULT_PROFILE_ID]; }, getActiveCapabilities: () => { return get().capabilities; }, }; });