Initial commit
Dieser Commit ist enthalten in:
157
frontend/src/components/Header.tsx
Normale Datei
157
frontend/src/components/Header.tsx
Normale Datei
@ -0,0 +1,157 @@
|
||||
import { useState } from 'react'
|
||||
import { useThemeStore } from '../stores/themeStore'
|
||||
import { SunIcon, MoonIcon } from './icons'
|
||||
import { useAuthStore } from '../stores/authStore'
|
||||
import { authApi } from '../services/api'
|
||||
import { usePermissions } from '../hooks/usePermissions'
|
||||
import WindowControls from './WindowControls'
|
||||
|
||||
export default function Header() {
|
||||
const { isDarkMode, toggleTheme } = useThemeStore()
|
||||
const { user, isAuthenticated, login, logout } = useAuthStore()
|
||||
const { canAccessAdminPanel } = usePermissions()
|
||||
const [showLogin, setShowLogin] = useState(false)
|
||||
const [loginForm, setLoginForm] = useState({ username: '', password: '' })
|
||||
const [loginError, setLoginError] = useState('')
|
||||
const [loginLoading, setLoginLoading] = useState(false)
|
||||
|
||||
const handleLogin = async (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
setLoginError('')
|
||||
setLoginLoading(true)
|
||||
|
||||
try {
|
||||
const response = await authApi.login(loginForm.username, loginForm.password)
|
||||
login(response.user, response.token)
|
||||
localStorage.setItem('token', response.token)
|
||||
setShowLogin(false)
|
||||
setLoginForm({ username: '', password: '' })
|
||||
} catch (error: any) {
|
||||
setLoginError(error.response?.data?.message || 'Login fehlgeschlagen')
|
||||
} finally {
|
||||
setLoginLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleLogout = () => {
|
||||
logout()
|
||||
localStorage.removeItem('token')
|
||||
}
|
||||
|
||||
return (
|
||||
<header className="bg-tertiary border-b border-primary h-16 flex items-center justify-between px-container relative -webkit-app-region-drag">
|
||||
<div className="flex items-center space-x-4">
|
||||
<h2 className="text-title-dialog font-poppins font-semibold text-primary">
|
||||
SkillMate
|
||||
</h2>
|
||||
|
||||
{/* Login/Logout Section */}
|
||||
<div className="flex items-center space-x-2 -webkit-app-region-no-drag">
|
||||
{!isAuthenticated ? (
|
||||
<div className="relative">
|
||||
<button
|
||||
onClick={() => setShowLogin(!showLogin)}
|
||||
className="btn-secondary text-sm px-3 py-1 h-8"
|
||||
>
|
||||
Anmelden
|
||||
</button>
|
||||
|
||||
{/* Login Dropdown */}
|
||||
{showLogin && (
|
||||
<div className="absolute top-full left-0 mt-2 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg shadow-lg p-4 w-64 z-50">
|
||||
<form onSubmit={handleLogin} className="space-y-3">
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Benutzername"
|
||||
value={loginForm.username}
|
||||
onChange={(e) => setLoginForm(prev => ({ ...prev, username: e.target.value }))}
|
||||
className="input-field w-full text-sm"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
type="password"
|
||||
placeholder="Passwort"
|
||||
value={loginForm.password}
|
||||
onChange={(e) => setLoginForm(prev => ({ ...prev, password: e.target.value }))}
|
||||
className="input-field w-full text-sm"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
{loginError && (
|
||||
<p className="text-red-600 text-xs">{loginError}</p>
|
||||
)}
|
||||
<div className="flex space-x-2">
|
||||
<button
|
||||
type="submit"
|
||||
disabled={loginLoading}
|
||||
className="btn-primary text-sm px-3 py-1 h-8 flex-1"
|
||||
>
|
||||
{loginLoading ? 'Wird angemeldet...' : 'Anmelden'}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowLogin(false)}
|
||||
className="btn-secondary text-sm px-3 py-1 h-8"
|
||||
>
|
||||
Abbrechen
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center space-x-2">
|
||||
<span className="text-secondary text-sm">{user?.username}</span>
|
||||
<div className="w-8 h-8 rounded-full bg-primary-blue text-white flex items-center justify-center font-semibold">
|
||||
{user?.username.charAt(0).toUpperCase()}
|
||||
</div>
|
||||
{canAccessAdminPanel() && (
|
||||
<a
|
||||
href="http://localhost:3002"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="btn-secondary text-sm px-3 py-1 h-8"
|
||||
>
|
||||
Admin
|
||||
</a>
|
||||
)}
|
||||
<button
|
||||
onClick={handleLogout}
|
||||
className="btn-secondary text-sm px-3 py-1 h-8"
|
||||
>
|
||||
Abmelden
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-4">
|
||||
{/* Theme Toggle Slider - moved to the right */}
|
||||
<div className="flex items-center space-x-2 -webkit-app-region-no-drag">
|
||||
<SunIcon className="w-4 h-4 text-gray-500" />
|
||||
<button
|
||||
onClick={toggleTheme}
|
||||
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 ${
|
||||
isDarkMode ? 'bg-blue-600' : 'bg-gray-200'
|
||||
}`}
|
||||
aria-label="Theme umschalten"
|
||||
>
|
||||
<span
|
||||
className={`inline-block h-4 w-4 transform rounded-full bg-white transition ${
|
||||
isDarkMode ? 'translate-x-6' : 'translate-x-1'
|
||||
}`}
|
||||
/>
|
||||
</button>
|
||||
<MoonIcon className="w-4 h-4 text-gray-500" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<WindowControls />
|
||||
</header>
|
||||
)
|
||||
}
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren