/** * useActiveRole Composable * * Client-side state management for user's active role (RoleSwitcher) * * Features: * - Reactive active role state * - List of all roles with approval status * - Switch role function with server validation * - Admin change notification flag * * Usage: * ```vue * const { activeRole, roles, roleChangedByAdmin, switchRole, fetchRoleStatus } = useActiveRole() * * // Fetch current status (validates server-side) * await fetchRoleStatus() * * // Switch role * await switchRole('educator') * ``` */ export interface RoleWithStatus { code: string displayName: string description: string hasRole: boolean requiresApproval: boolean } export function useActiveRole() { // Use useState for shared state across the app const activeRole = useState('activeRole', () => 'private') const roles = useState('roles', () => []) const roleChangedByAdmin = useState('roleChangedByAdmin', () => false) const loading = useState('roleLoading', () => false) const error = useState('roleError', () => null) /** * Fetch current role status from server * - Validates active role (TTL-based) * - Fetches all roles with approval status * - Detects if admin changed user's roles */ async function fetchRoleStatus() { loading.value = true error.value = null try { const data = await $fetch('/api/user/role-status') activeRole.value = data.activeRoleCode roles.value = data.roles roleChangedByAdmin.value = data.roleChangedByAdmin return data } catch (err: any) { // 401 during session initialization is normal - watch() will retry successfully if (err.statusCode === 401) { console.debug('Role status fetch: Session not ready yet, will retry via watch()') return null } // Other errors are real problems console.error('Failed to fetch role status:', err) error.value = 'Fehler beim Laden der Rollen' throw err } finally { loading.value = false } } /** * Switch to a different role * - Validates server-side that user has the role * - Updates session + database * - Refreshes products list if on products page * * @param roleCode - Role to switch to ('private', 'educator', 'company') * @throws Error if user doesn't have the role or if switch fails */ async function switchRole(roleCode: string) { loading.value = true error.value = null try { await $fetch('/api/user/active-role', { method: 'PATCH', body: { roleCode }, }) // Update local state activeRole.value = roleCode roleChangedByAdmin.value = false // Refresh all product list pages (role-based visibility) // Note: Product detail pages will handle visibility via API 404 check await Promise.all([ refreshNuxtData('products-list'), // Main products page refreshNuxtData('educator-products'), // Educator products page refreshNuxtData('experimenta-products'), // Experimenta products page ]) return true } catch (err: any) { console.error('Failed to switch role:', err) error.value = err.data?.message || 'Fehler beim Wechseln der Rolle' throw err } finally { loading.value = false } } /** * Reset all role state (called on logout) */ function resetRoles() { activeRole.value = 'private' roles.value = [] roleChangedByAdmin.value = false loading.value = false error.value = null } /** * Get roles that user actually has (approved only) */ const approvedRoles = computed(() => roles.value.filter((r) => r.hasRole)) /** * Check if user has multiple roles */ const hasMultipleRoles = computed(() => approvedRoles.value.length > 1) /** * Auto-fetch roles when user logs in * This ensures the role button shows the correct role immediately after login */ const { loggedIn } = useUserSession() // Initial fetch if already logged in if (loggedIn.value) { callOnce('init-roles', () => fetchRoleStatus()) } // Watch for login changes - fetch roles when user logs in watch(loggedIn, (newLoggedIn) => { if (newLoggedIn) { fetchRoleStatus() } }) return { // State (useState already returns writable refs) activeRole, roles, approvedRoles, hasMultipleRoles, roleChangedByAdmin, loading, error, // Actions fetchRoleStatus, switchRole, resetRoles, } }