196 lines
6.2 KiB
TypeScript
196 lines
6.2 KiB
TypeScript
/**
|
||
* UserSection Component
|
||
*
|
||
* Zeigt Benutzerinformationen und Logout-Button in der Sidebar.
|
||
*/
|
||
|
||
import React, { useState } from 'react';
|
||
import { useNavigate } from 'react-router-dom';
|
||
import { useCurrentUser } from '../../hooks/useUsers';
|
||
import { NotificationBell } from '../NotificationBell';
|
||
import { _isOnboardingHidden, _showOnboarding } from '../OnboardingAssistant';
|
||
import styles from './UserSection.module.css';
|
||
|
||
import { useLanguage } from '../../providers/language/LanguageContext';
|
||
|
||
export const UserSection: React.FC = () => {
|
||
const { t } = useLanguage();
|
||
|
||
const { user, logout } = useCurrentUser();
|
||
const navigate = useNavigate();
|
||
const [isLoggingOut, setIsLoggingOut] = useState(false);
|
||
const [showMenu, setShowMenu] = useState(false);
|
||
const [showLegalModal, setShowLegalModal] = useState(false);
|
||
const [onboardingHidden, setOnboardingHidden] = useState(() => _isOnboardingHidden());
|
||
|
||
const handleLogout = async () => {
|
||
setIsLoggingOut(true);
|
||
try {
|
||
await logout();
|
||
} catch (error) {
|
||
console.error('Logout failed:', error);
|
||
setIsLoggingOut(false);
|
||
}
|
||
};
|
||
|
||
const handleSettings = () => {
|
||
navigate('/settings');
|
||
setShowMenu(false);
|
||
};
|
||
|
||
const handleBilling = () => {
|
||
navigate('/billing/transactions');
|
||
setShowMenu(false);
|
||
};
|
||
|
||
const handleLegal = () => {
|
||
setShowLegalModal(true);
|
||
setShowMenu(false);
|
||
};
|
||
|
||
const handleOnboarding = () => {
|
||
_showOnboarding();
|
||
setOnboardingHidden(false);
|
||
navigate('/', { state: { showOnboarding: Date.now() } });
|
||
setShowMenu(false);
|
||
};
|
||
|
||
if (!user) {
|
||
return null;
|
||
}
|
||
|
||
// Initialen für Avatar
|
||
const initials = (() => {
|
||
const name = user.fullName || user.username || '';
|
||
const parts = name.trim().split(/\s+/);
|
||
if (parts.length >= 2) return (parts[0][0] + parts[parts.length - 1][0]).toLocaleUpperCase();
|
||
return [...name.trim()].slice(0, 2).join('').toLocaleUpperCase() || '?';
|
||
})();
|
||
|
||
return (
|
||
<div className={styles.userSection}>
|
||
{/* Notification Bell */}
|
||
<NotificationBell className={styles.notificationBell} />
|
||
|
||
<button
|
||
className={styles.userButton}
|
||
onClick={() => { setShowMenu(!showMenu); setOnboardingHidden(_isOnboardingHidden()); }}
|
||
aria-expanded={showMenu}
|
||
>
|
||
<div className={styles.avatar}>
|
||
{initials}
|
||
</div>
|
||
<div className={styles.userInfo}>
|
||
<span className={styles.userName}>{user.fullName || user.username}</span>
|
||
<span className={styles.userEmail}>{user.email}</span>
|
||
</div>
|
||
<span className={styles.chevron}>
|
||
{showMenu ? '▲' : '▼'}
|
||
</span>
|
||
</button>
|
||
|
||
{showMenu && (
|
||
<div className={styles.menu}>
|
||
<button
|
||
className={styles.menuItem}
|
||
onClick={handleBilling}
|
||
>
|
||
<span className={styles.menuIcon}>💰</span>
|
||
{t('Guthaben')}
|
||
</button>
|
||
|
||
<button
|
||
className={styles.menuItem}
|
||
onClick={handleSettings}
|
||
>
|
||
<span className={styles.menuIcon}>⚙️</span>
|
||
{t('Einstellungen')}
|
||
</button>
|
||
|
||
{onboardingHidden && (
|
||
<button
|
||
className={styles.menuItem}
|
||
onClick={handleOnboarding}
|
||
>
|
||
<span className={styles.menuIcon}>{'\uD83E\uDDED'}</span>
|
||
{t('Onboarding-Assistent')}
|
||
</button>
|
||
)}
|
||
|
||
<button
|
||
className={styles.menuItem}
|
||
onClick={handleLegal}
|
||
>
|
||
<span className={styles.menuIcon}>📜</span>
|
||
{t('Rechtliche Hinweise')}
|
||
</button>
|
||
|
||
<div className={styles.menuDivider} />
|
||
|
||
<button
|
||
className={styles.menuItem}
|
||
onClick={handleLogout}
|
||
disabled={isLoggingOut}
|
||
>
|
||
<span className={styles.menuIcon}>🚪</span>
|
||
{isLoggingOut ? t('Abmelden...') : t('Abmelden')}
|
||
</button>
|
||
</div>
|
||
)}
|
||
|
||
{/* Legal Modal */}
|
||
{showLegalModal && (
|
||
<div className={styles.modalOverlay}>
|
||
<div className={styles.modal}>
|
||
<div className={styles.modalHeader}>
|
||
<h2>{t('Legal notices')}</h2>
|
||
<button
|
||
className={styles.modalClose}
|
||
onClick={() => setShowLegalModal(false)}
|
||
>
|
||
✕
|
||
</button>
|
||
</div>
|
||
<div className={styles.modalContent}>
|
||
<div className={styles.legalSection}>
|
||
<h3>{t('Datenverarbeitung und KI-Nutzung')}</h3>
|
||
|
||
<h4>{t('userSection.1EinwilligungZurDatenverarbeitung')}</h4>
|
||
<p>{t('By using this application')}</p>
|
||
<ul>
|
||
<li>{t('You authorize the collection and processing')}</li>
|
||
<li>{t('User data may be shared with third-party providers of')}</li>
|
||
<li>{t('This consent extends to')}</li>
|
||
</ul>
|
||
|
||
<h4>{t('userSection.2AnerkennungDerKiverarbeitungsrisiken')}</h4>
|
||
<ul>
|
||
<li>{t('AI systems may produce unexpected or inaccurate')}</li>
|
||
<li>{t('AI services can process data according to their')}</li>
|
||
<li>{t('Despite security measures, data may be vulnerable')}</li>
|
||
</ul>
|
||
|
||
<h4>{t('userSection.3Haftungsausschluss')}</h4>
|
||
<p>{t('To the fullest extent possible, you waive')}</p>
|
||
</div>
|
||
|
||
<div className={styles.legalLinks}>
|
||
<a href="/poweron-privacy.html" target="_blank" rel="noopener noreferrer">
|
||
{t('Datenschutzrichtlinie')}
|
||
</a>
|
||
<a href="/poweron-terms.html" target="_blank" rel="noopener noreferrer">
|
||
{t('Nutzungsbedingungen')}
|
||
</a>
|
||
<a href="/poweron-home.html" target="_blank" rel="noopener noreferrer">
|
||
{t('Über PowerOn')}
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default UserSection;
|