efc72b720e
- scoreCalculator: apply dataQuality/confidence modifiers to finalScore (were computed but hardcoded to 0) - authService: call queryClient.clear() on logout to prevent cross-session data leakage - queryClient: extract to src/lib/queryClient.ts singleton so services can access it without circular imports - matchSyncService: new service layer owns match-generation logic; MockupNeedProvider no longer imports other providers directly - hooks (11 files): add onError + German toast feedback to every useMutation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
137 lines
4.6 KiB
TypeScript
137 lines
4.6 KiB
TypeScript
import { useSessionStore } from '../stores/sessionStore'
|
|
import type { MockUser } from '../stores/sessionStore'
|
|
import type { ItemResponse } from './types'
|
|
import { UserRole, WorkspaceType } from '../domain/enums'
|
|
import { getPermissions, getAccessibleWorkspaces } from '../lib/permissions'
|
|
import type { Permission } from '../lib/permissions'
|
|
import { queryClient } from '../lib/queryClient'
|
|
|
|
// Mock organizations for org switching
|
|
const MOCK_ORGANIZATIONS: { id: string; name: string }[] = [
|
|
{ id: 'org-wincasa', name: 'Wincasa AG' },
|
|
{ id: 'org-mobimo', name: 'Mobimo Management AG' },
|
|
{ id: 'org-ubs', name: 'UBS Asset Management RE' },
|
|
]
|
|
|
|
// Demo user presets per role
|
|
const DEMO_USERS: Record<UserRole, MockUser> = {
|
|
[UserRole.SUPER_ADMIN]: {
|
|
id: 'user-super',
|
|
email: 'super@ideal-sharing.ch',
|
|
name: 'Super Admin',
|
|
role: UserRole.SUPER_ADMIN,
|
|
organizationId: 'org-wincasa',
|
|
organizationName: 'Wincasa AG',
|
|
allowedWorkspaces: [WorkspaceType.SUPPLY, WorkspaceType.DEMAND],
|
|
},
|
|
[UserRole.ORGANIZATION_ADMIN]: {
|
|
id: 'user-001',
|
|
email: 'admin@ideal-sharing.ch',
|
|
name: 'Admin User',
|
|
role: UserRole.ORGANIZATION_ADMIN,
|
|
organizationId: 'org-wincasa',
|
|
organizationName: 'Wincasa AG',
|
|
allowedWorkspaces: [WorkspaceType.SUPPLY, WorkspaceType.DEMAND],
|
|
},
|
|
[UserRole.PROPERTY_MANAGER]: {
|
|
id: 'user-pm',
|
|
email: 'pm@ideal-sharing.ch',
|
|
name: 'Property Manager',
|
|
role: UserRole.PROPERTY_MANAGER,
|
|
organizationId: 'org-wincasa',
|
|
organizationName: 'Wincasa AG',
|
|
allowedWorkspaces: getAccessibleWorkspaces(UserRole.PROPERTY_MANAGER),
|
|
},
|
|
[UserRole.REVIEWER]: {
|
|
id: 'user-rev',
|
|
email: 'reviewer@ideal-sharing.ch',
|
|
name: 'Reviewer',
|
|
role: UserRole.REVIEWER,
|
|
organizationId: 'org-wincasa',
|
|
organizationName: 'Wincasa AG',
|
|
allowedWorkspaces: getAccessibleWorkspaces(UserRole.REVIEWER),
|
|
},
|
|
[UserRole.OWNER_VIEWER]: {
|
|
id: 'user-ov',
|
|
email: 'owner@ideal-sharing.ch',
|
|
name: 'Owner Viewer',
|
|
role: UserRole.OWNER_VIEWER,
|
|
organizationId: 'org-wincasa',
|
|
organizationName: 'Wincasa AG',
|
|
allowedWorkspaces: getAccessibleWorkspaces(UserRole.OWNER_VIEWER),
|
|
},
|
|
[UserRole.DEMAND_USER]: {
|
|
id: 'user-dem',
|
|
email: 'demand@ideal-sharing.ch',
|
|
name: 'Demand User',
|
|
role: UserRole.DEMAND_USER,
|
|
organizationId: 'org-mobimo',
|
|
organizationName: 'Mobimo Management AG',
|
|
allowedWorkspaces: getAccessibleWorkspaces(UserRole.DEMAND_USER),
|
|
},
|
|
}
|
|
|
|
export const authService = {
|
|
async getCurrentUser(): Promise<ItemResponse<MockUser | null>> {
|
|
const data = useSessionStore.getState().currentUser
|
|
return { data }
|
|
},
|
|
|
|
async getCurrentOrganization(): Promise<ItemResponse<{ id: string; name: string } | null>> {
|
|
const { activeOrganizationId } = useSessionStore.getState()
|
|
const org = MOCK_ORGANIZATIONS.find((o) => o.id === activeOrganizationId) ?? null
|
|
return { data: org }
|
|
},
|
|
|
|
async login(email: string, _password: string): Promise<ItemResponse<MockUser>> {
|
|
const existing = Object.values(DEMO_USERS).find((u) => u.email === email)
|
|
const user: MockUser = existing ?? {
|
|
id: 'user-001',
|
|
email,
|
|
name: 'Admin User',
|
|
role: UserRole.ORGANIZATION_ADMIN,
|
|
organizationId: 'org-wincasa',
|
|
organizationName: 'Wincasa AG',
|
|
allowedWorkspaces: [WorkspaceType.SUPPLY, WorkspaceType.DEMAND],
|
|
}
|
|
useSessionStore.getState().login(user)
|
|
return { data: user }
|
|
},
|
|
|
|
async logout(): Promise<ItemResponse<void>> {
|
|
useSessionStore.getState().logout()
|
|
// Clear all cached query data so stale data from the previous session
|
|
// cannot leak to the next user who logs in on the same browser tab.
|
|
queryClient.clear()
|
|
return { data: undefined }
|
|
},
|
|
|
|
async isAuthenticated(): Promise<ItemResponse<boolean>> {
|
|
const data = useSessionStore.getState().isAuthenticated
|
|
return { data }
|
|
},
|
|
|
|
async switchDemoRole(role: UserRole): Promise<ItemResponse<MockUser>> {
|
|
const user = DEMO_USERS[role]
|
|
useSessionStore.getState().login(user)
|
|
return { data: user }
|
|
},
|
|
|
|
async switchOrganization(organizationId: string): Promise<ItemResponse<void>> {
|
|
const org = MOCK_ORGANIZATIONS.find((o) => o.id === organizationId)
|
|
if (org) {
|
|
const state = useSessionStore.getState()
|
|
if (state.currentUser) {
|
|
state.login({ ...state.currentUser, organizationId: org.id, organizationName: org.name })
|
|
} else {
|
|
state.switchOrganization(organizationId)
|
|
}
|
|
}
|
|
return { data: undefined }
|
|
},
|
|
|
|
async getPermissions(user: MockUser): Promise<ItemResponse<Permission[]>> {
|
|
return { data: getPermissions(user) }
|
|
},
|
|
}
|