frontend_nyla/src/components/Sidebar/SidebarUser.tsx

196 lines
No EOL
7.3 KiB
TypeScript

import React, { useState, useEffect, useRef } from 'react'
import { useMsal } from '@azure/msal-react'
import { FaSignOutAlt } from 'react-icons/fa'
import styles from './SidebarStyles/SidebarUser.module.css'
import { User } from '../../hooks/useUsers'
import { SidebarUserProps } from './sidebarTypes';
import { getUserDataCache, CachedUserData } from '../../utils/userCache';
import { useCurrentUser } from '../../hooks/useUsers';
const SidebarUser: React.FC<SidebarUserProps> = ({ isMinimized = false }) => {
const { instance } = useMsal();
const { logout } = useCurrentUser(); // Only use logout function from hook
// Local state for user data created from cached data
const [user, setUser] = useState<User | null>(null);
const [userError, setUserError] = useState<string | null>(null);
const [cachedUserData, setCachedUserData] = useState<CachedUserData | null>(null);
const [showLogoutMenu, setShowLogoutMenu] = useState(false);
const [isLoggingOut, setIsLoggingOut] = useState(false);
const userSectionRef = useRef<HTMLDivElement>(null);
// Function to get initials from full name
const getInitials = (fullName: string): string => {
return fullName
.split(' ')
.map(name => name.charAt(0).toUpperCase())
.join('')
.substring(0, 2); // Limit to 2 characters
};
const handleUserClick = () => {
setShowLogoutMenu(!showLogoutMenu);
};
const handleLogout = async () => {
if (!user || isLoggingOut) return;
setIsLoggingOut(true);
try {
// Pass MSAL instance for Microsoft authentication
if (user.authenticationAuthority === 'msft') {
await logout(instance);
} else {
await logout();
}
setShowLogoutMenu(false);
} catch (error) {
console.error('Logout failed:', error);
// Keep the menu open if logout fails so user can try again
setIsLoggingOut(false);
}
};
// Load cached user data on mount and when user updates
useEffect(() => {
const loadCachedUserData = () => {
const cached = getUserDataCache();
setCachedUserData(cached);
if (cached?.id) {
// Create a User object from cached data with fallback values
const userData: User = {
id: cached.id,
username: cached.username,
email: cached.email || cached.username, // Use email or username as fallback
fullName: cached.fullName || cached.username.split('@')[0] || cached.username,
language: cached.language || 'de', // Default language
enabled: cached.enabled ?? true, // Assume enabled if logged in
roleLabels: cached.roleLabels || [],
authenticationAuthority: cached.authenticationAuthority || 'local',
mandateId: cached.mandateId || ''
};
setUser(userData);
setUserError(null);
} else {
setUser(null);
}
};
loadCachedUserData();
}, []); // Empty dependency array - only run on mount
// Listen for user updates from settings page
useEffect(() => {
const handleUserUpdate = () => {
// Refresh cached user data when user info is updated
const cached = getUserDataCache();
setCachedUserData(cached);
if (cached?.id) {
const userData: User = {
id: cached.id,
username: cached.username,
email: cached.email || cached.username,
fullName: cached.fullName || cached.username.split('@')[0] || cached.username,
language: cached.language || 'de',
enabled: cached.enabled ?? true,
roleLabels: cached.roleLabels || [],
authenticationAuthority: cached.authenticationAuthority || 'local',
mandateId: cached.mandateId || ''
};
setUser(userData);
setUserError(null);
} else {
setUser(null);
}
};
window.addEventListener('userInfoUpdated', handleUserUpdate);
return () => {
window.removeEventListener('userInfoUpdated', handleUserUpdate);
};
}, []); // Empty dependency array - only set up listener once
// Close popup when clicking outside
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (userSectionRef.current && !userSectionRef.current.contains(event.target as Node)) {
setShowLogoutMenu(false);
}
};
if (showLogoutMenu) {
document.addEventListener('mousedown', handleClickOutside);
}
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [showLogoutMenu]);
if (!cachedUserData) {
return (
<div className={`${styles.user_section} ${isMinimized ? styles.minimized : ''}`}>
<div className={styles.userContainer}>Lädt...</div>
</div>
);
}
if (userError) {
return (
<div className={`${styles.user_section} ${isMinimized ? styles.minimized : ''}`}>
<div className={styles.userContainer}>Fehler beim Laden des Benutzerprofils</div>
</div>
);
}
if (!user) {
return (
<div className={`${styles.user_section} ${isMinimized ? styles.minimized : ''}`}>
<div className={styles.userContainer}>Kein Benutzer gefunden</div>
</div>
);
}
return (
<div
ref={userSectionRef}
className={`${styles.user_section} ${isMinimized ? styles.minimized : ''}`}
>
{showLogoutMenu && (
<div className={`${styles.logout_popup} ${isMinimized ? styles.logout_popup_minimized : ''}`}>
<button
className={styles.logout_menu_button}
onClick={handleLogout}
disabled={isLoggingOut}
>
<FaSignOutAlt className={styles.logout_icon} />
{!isMinimized && (isLoggingOut ? 'Abmelden...' : 'Abmelden')}
</button>
</div>
)}
<div
className={`${styles.user_info} ${showLogoutMenu ? styles.notClickable : styles.clickable}`}
onClick={handleUserClick}
>
<div className={styles.user_header}>
<div className={styles.user_avatar}>
{getInitials(user.fullName)}
</div>
{!isMinimized && (
<div className={styles.text_content}>
<h1>{user.fullName}</h1>
<p className={styles.username}>{user.username}</p>
</div>
)}
</div>
</div>
</div>
)
}
export default SidebarUser;