Files
web-cad/frontend/src/components/SettingsModal.tsx
T

190 lines
8.1 KiB
TypeScript

import React, { useState } from 'react';
import { useAuth } from '../contexts/AuthContext';
import PluginManager from './PluginManager';
export interface SettingsModalProps {
open: boolean;
onClose: () => void;
}
type SettingsTab = 'personal' | 'password' | 'language' | 'theme' | 'users' | 'plugins' | 'ai';
const SettingsModal: React.FC<SettingsModalProps> = ({ open, onClose }) => {
const { user } = useAuth();
const [activeTab, setActiveTab] = useState<SettingsTab>('personal');
const [displayName, setDisplayName] = useState(user?.name || '');
const [oldPassword, setOldPassword] = useState('');
const [newPassword, setNewPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [language, setLanguage] = useState('de');
const [themeMode, setThemeMode] = useState<'light' | 'dark'>('dark');
const [accentColor, setAccentColor] = useState('#2563eb');
const [aiProvider, setAiProvider] = useState('openrouter');
const [aiModel, setAiModel] = useState('gpt-4o');
const [aiApiKey, setAiApiKey] = useState('');
const [pwMessage, setPwMessage] = useState('');
if (!open) return null;
const isAdmin = user?.role === 'admin';
const initials = (user?.name || '?').split(' ').map(w => w[0]).join('').slice(0, 2).toUpperCase();
const tabs: Array<{ id: SettingsTab; label: string; adminOnly?: boolean }> = [
{ id: 'personal', label: 'Persönlich' },
{ id: 'password', label: 'Passwort' },
{ id: 'language', label: 'Sprache' },
{ id: 'theme', label: 'Theme' },
{ id: 'users', label: 'Benutzer', adminOnly: true },
{ id: 'plugins', label: 'Plugins', adminOnly: true },
{ id: 'ai', label: 'KI' },
];
const visibleTabs = tabs.filter(t => !t.adminOnly || isAdmin);
const handlePasswordChange = () => {
if (!oldPassword || !newPassword || !confirmPassword) {
setPwMessage('Bitte alle Felder ausfüllen.');
return;
}
if (newPassword !== confirmPassword) {
setPwMessage('Neue Passwörter stimmen nicht überein.');
return;
}
if (newPassword.length < 6) {
setPwMessage('Passwort muss mindestens 6 Zeichen lang sein.');
return;
}
setPwMessage('Passwort erfolgreich geändert.');
setOldPassword('');
setNewPassword('');
setConfirmPassword('');
};
const renderTabContent = () => {
switch (activeTab) {
case 'personal':
return (
<div className="settings-tab-content">
<label className="settings-label">Anzeigename</label>
<input className="settings-input" type="text" value={displayName} onChange={(e) => setDisplayName(e.target.value)} />
<label className="settings-label">E-Mail</label>
<input className="settings-input" type="email" value={user?.email || ''} readOnly style={{ opacity: 0.6 }} />
<label className="settings-label">Avatar</label>
<div className="settings-avatar-preview">{initials}</div>
</div>
);
case 'password':
return (
<div className="settings-tab-content">
<label className="settings-label">Altes Passwort</label>
<input className="settings-input" type="password" value={oldPassword} onChange={(e) => setOldPassword(e.target.value)} />
<label className="settings-label">Neues Passwort</label>
<input className="settings-input" type="password" value={newPassword} onChange={(e) => setNewPassword(e.target.value)} />
<label className="settings-label">Passwort bestätigen</label>
<input className="settings-input" type="password" value={confirmPassword} onChange={(e) => setConfirmPassword(e.target.value)} />
{pwMessage && <div className="settings-message">{pwMessage}</div>}
<button className="settings-btn" onClick={handlePasswordChange}>Passwort ändern</button>
</div>
);
case 'language':
return (
<div className="settings-tab-content">
<label className="settings-label">Sprache</label>
<select className="settings-input" value={language} onChange={(e) => setLanguage(e.target.value)}>
<option value="de">Deutsch</option>
<option value="en">English</option>
</select>
</div>
);
case 'theme':
return (
<div className="settings-tab-content">
<label className="settings-label">Erscheinungsbild</label>
<div className="settings-toggle-group">
<button className={`settings-toggle-btn${themeMode === 'light' ? ' active' : ''}`} onClick={() => setThemeMode('light')}>Hell</button>
<button className={`settings-toggle-btn${themeMode === 'dark' ? ' active' : ''}`} onClick={() => setThemeMode('dark')}>Dunkel</button>
</div>
<label className="settings-label">Akzentfarbe</label>
<div className="settings-color-picker">
<input type="color" value={accentColor} onChange={(e) => setAccentColor(e.target.value)} />
<span className="settings-color-value">{accentColor}</span>
</div>
</div>
);
case 'users':
return (
<div className="settings-tab-content">
<div className="settings-users-header">
<strong>Benutzerverwaltung</strong>
<button className="settings-btn">Benutzer hinzufügen</button>
</div>
<div className="settings-user-list">
<div className="settings-user-row">
<div className="settings-user-avatar">LM</div>
<div className="settings-user-info">
<div className="settings-user-name">Leopold M.</div>
<div className="settings-user-email">admin@example.com</div>
</div>
<span className="settings-user-role">Admin</span>
<button className="settings-btn-danger">Löschen</button>
</div>
</div>
</div>
);
case 'plugins':
return (
<div className="settings-tab-content">
<PluginManager />
</div>
);
case 'ai':
return (
<div className="settings-tab-content">
<label className="settings-label">KI-Anbieter</label>
<select className="settings-input" value={aiProvider} onChange={(e) => setAiProvider(e.target.value)}>
<option value="openrouter">OpenRouter</option>
<option value="openai">OpenAI</option>
<option value="anthropic">Anthropic</option>
<option value="local">Lokal (Ollama)</option>
</select>
<label className="settings-label">Modell</label>
<select className="settings-input" value={aiModel} onChange={(e) => setAiModel(e.target.value)}>
<option value="gpt-4o">GPT-4o</option>
<option value="gpt-4o-mini">GPT-4o mini</option>
<option value="claude-3.5-sonnet">Claude 3.5 Sonnet</option>
<option value="llama-3.3-70b">Llama 3.3 70B</option>
</select>
<label className="settings-label">API-Key</label>
<input className="settings-input" type="password" value={aiApiKey} onChange={(e) => setAiApiKey(e.target.value)} placeholder="••••••••••••" />
</div>
);
default:
return null;
}
};
return (
<div className="settings-modal-overlay" onClick={onClose}>
<div className="settings-modal" onClick={(e) => e.stopPropagation()}>
<button className="settings-modal-close" onClick={onClose} aria-label="Schließen"></button>
<div className="settings-modal-tabs">
{visibleTabs.map((tab) => (
<button
key={tab.id}
className={`settings-modal-tab${activeTab === tab.id ? ' active' : ''}`}
onClick={() => setActiveTab(tab.id)}
>
{tab.label}
</button>
))}
</div>
<div className="settings-modal-content">
{renderTabContent()}
</div>
</div>
</div>
);
};
export default SettingsModal;