import { useState, useEffect } from 'react' import { Plus, Trash2, Pencil, Check, X, Shield, Key } from 'lucide-react' import { Link } from 'react-router-dom' import { useAuth } from '../context/AuthContext' import { api } from '../utils/api' const COLORS = ['#1D9E75','#378ADD','#D85A30','#EF9F27','#7F77DD','#D4537E','#639922','#888780'] function Avatar({ profile, size=36 }) { const initials = profile.name.split(' ').map(n=>n[0]).join('').toUpperCase().slice(0,2) return (
{initials}
) } function NewProfileForm({ onSave, onCancel }) { const [form, setForm] = useState({ name:'', pin:'', email:'', avatar_color:COLORS[0], sex:'m', height:'', auth_type:'pin', session_days:30 }) const [error, setError] = useState(null) const set = (k,v) => setForm(f=>({...f,[k]:v})) const handleSave = async () => { if (!form.name.trim()) return setError('Name eingeben') if (form.pin.length < 4) return setError('PIN mind. 4 Zeichen') try { await onSave({...form, height:parseFloat(form.height)||178}) } catch(e) { setError(e.message) } } return (
Neues Profil
set('name',e.target.value)} autoFocus/>
Farbe
{COLORS.map(c=>(
set('avatar_color',c)} style={{width:24,height:24,borderRadius:'50%',background:c,cursor:'pointer', border:`3px solid ${form.avatar_color===c?'white':'transparent'}`, boxShadow:form.avatar_color===c?`0 0 0 2px ${c}`:'none'}}/> ))}
set('height',e.target.value)}/> cm
set('email',e.target.value)}/>
set('pin',e.target.value)}/>
{error &&
{error}
}
) } function EmailEditor({ profileId, currentEmail, onSaved }) { const [email, setEmail] = useState(currentEmail||'') const [msg, setMsg] = useState(null) const save = async () => { const token = localStorage.getItem('bodytrack_token')||'' await fetch(`/api/admin/profiles/${profileId}/email`, { method:'PUT', headers:{'Content-Type':'application/json','X-Auth-Token':token}, body: JSON.stringify({email}) }) setMsg('✓ Gespeichert'); onSaved() setTimeout(()=>setMsg(null),2000) } return (
setEmail(e.target.value)} style={{flex:1}}/> {msg && {msg}}
) } function ProfileCard({ profile, currentId, onRefresh }) { const [expanded, setExpanded] = useState(false) const [perms, setPerms] = useState({ role: profile.role || 'user', }) const [saving, setSaving] = useState(false) const [newPin, setNewPin] = useState('') const [pinMsg, setPinMsg] = useState(null) const isSelf = profile.id === currentId const savePerms = async () => { setSaving(true) try { await api.adminSetPermissions(profile.id, { role: perms.role, }) await onRefresh() } finally { setSaving(false) } } const savePin = async () => { if (newPin.length < 4) return setPinMsg('Mind. 4 Zeichen') try { await fetch(`/api/admin/profiles/${profile.id}/pin`, { method:'PUT', headers:{'Content-Type':'application/json', 'X-Auth-Token': localStorage.getItem('bodytrack_token')||''}, body: JSON.stringify({pin: newPin}) }) setNewPin(''); setPinMsg('✓ PIN geändert') setTimeout(()=>setPinMsg(null),2000) } catch(e) { setPinMsg('Fehler: '+e.message) } } const deleteProfile = async () => { if (!confirm(`Profil "${profile.name}" und ALLE Daten löschen?`)) return await api.adminDeleteProfile(profile.id) await onRefresh() } return (
{profile.name} {profile.role==='admin' && 👑 Admin} {isSelf && Du}
Tier: {profile.tier || 'free'} · Email: {profile.email || 'nicht gesetzt'}
{!isSelf && ( )}
{expanded && (
BERECHTIGUNGEN
Rolle
{['user','admin'].map(r=>( ))}
Feature-Limits: Nutze die neue{' '} User Feature-Overrides {' '} Seite um individuelle Limits zu setzen.
E-MAIL (für Recovery & Zusammenfassungen)
PIN / PASSWORT ÄNDERN
setNewPin(e.target.value)} style={{flex:1}}/>
{pinMsg &&
{pinMsg}
}
)}
) } export default function AdminUsersPage() { const { session } = useAuth() const [profiles, setProfiles] = useState([]) const [creating, setCreating] = useState(false) const [loading, setLoading] = useState(true) const load = () => api.adminListProfiles().then(data=>{ setProfiles(data); setLoading(false) }) useEffect(()=>{ load() },[]) const handleCreate = async (form) => { await api.adminCreateProfile(form) setCreating(false) await load() } if (loading) return
return (

Benutzerverwaltung

👑 Profile anlegen, Rollen setzen und Recovery-E-Mail pro Nutzer pflegen. Feature-Limits über „User-Overrides“ in der Seitenleiste.
{creating && ( setCreating(false)}/> )} {profiles.map(p=>( ))} {!creating && ( )}
) }