fix: Render ProfileModal in App.jsx and support guest display name editing from Navbar

This commit is contained in:
Richard
2026-08-01 12:20:24 +02:00
parent 5f1607f0d3
commit 4b13e57fcb
4 changed files with 42 additions and 15 deletions
+1 -1
View File
@@ -11,7 +11,7 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<title>Schichtplaner — Veranstaltungsschichtpläne</title> <title>Schichtplaner — Veranstaltungsschichtpläne</title>
<script type="module" crossorigin src="/assets/index-BUskNRc4.js"></script> <script type="module" crossorigin src="/assets/index-AKhcitQN.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DHeBvKbG.css"> <link rel="stylesheet" crossorigin href="/assets/index-DHeBvKbG.css">
</head> </head>
<body class="bg-paper text-main font-sans antialiased min-h-screen"> <body class="bg-paper text-main font-sans antialiased min-h-screen">
+14
View File
@@ -651,6 +651,20 @@ export default function App() {
onSubmit={handleGuestSubmit} onSubmit={handleGuestSubmit}
/> />
)} )}
{showProfileModal && (
<ProfileModal
user={user}
skills={skills}
onClose={() => setShowProfileModal(false)}
onUserUpdated={(updatedUser) => {
setUser(updatedUser);
setShowProfileModal(false);
refreshEvents();
}}
onRefreshSkills={refreshSkills}
/>
)}
</div> </div>
); );
} }
+8 -4
View File
@@ -62,13 +62,17 @@ export default function Navbar({
</h1> </h1>
<div className="text-[10px] font-mono text-muted mt-1 uppercase tracking-wider flex items-center gap-1.5"> <div className="text-[10px] font-mono text-muted mt-1 uppercase tracking-wider flex items-center gap-1.5">
{user ? ( {user ? (
<span className="text-emerald-500 font-semibold">[ {user.display_name || user.username} ]</span> <span onClick={(e) => { e.stopPropagation(); onOpenProfile(); }} className="text-emerald-500 font-semibold hover:underline cursor-pointer">
[ {user.display_name || user.username} ]
</span>
) : savedGuestName ? ( ) : savedGuestName ? (
<span className="text-amber-400 font-semibold flex items-center gap-1"> <span onClick={(e) => { e.stopPropagation(); onOpenProfile(); }} className="text-amber-400 font-semibold flex items-center gap-1 hover:underline cursor-pointer" title="Klicken um Gast-Name zu ändern">
[ 👤 GAST: {savedGuestName} ] [ 👤 GAST: {savedGuestName} ]
</span> </span>
) : ( ) : (
<span className="text-amber-500 font-semibold">[ GAST-MODUS ]</span> <span onClick={(e) => { e.stopPropagation(); onOpenProfile(); }} className="text-amber-500 font-semibold hover:underline cursor-pointer" title="Klicken um Gast-Name einzutragen">
[ GAST-MODUS ]
</span>
)} )}
</div> </div>
</div> </div>
+19 -10
View File
@@ -4,7 +4,9 @@ import { apiFetch } from '../api/client';
import { getRandomSkillColor } from '../utils/colors'; import { getRandomSkillColor } from '../utils/colors';
export default function ProfileModal({ user, skills, onClose, onUserUpdated, onRefreshSkills }) { export default function ProfileModal({ user, skills, onClose, onUserUpdated, onRefreshSkills }) {
const [displayName, setDisplayName] = useState(user?.display_name || ''); const [displayName, setDisplayName] = useState(
user?.display_name || localStorage.getItem('guest_display_name') || ''
);
const [selectedSkillIds, setSelectedSkillIds] = useState( const [selectedSkillIds, setSelectedSkillIds] = useState(
user?.skills ? user.skills.map(s => s.id) : [] user?.skills ? user.skills.map(s => s.id) : []
); );
@@ -26,15 +28,22 @@ export default function ProfileModal({ user, skills, onClose, onUserUpdated, onR
setSavingProfile(true); setSavingProfile(true);
try { try {
const updatedUser = await apiFetch('/users/me/', { if (user) {
method: 'PATCH', const updatedUser = await apiFetch('/users/me/', {
body: JSON.stringify({ method: 'PATCH',
display_name: displayName.trim(), body: JSON.stringify({
skill_ids: selectedSkillIds display_name: displayName.trim(),
}) skill_ids: selectedSkillIds
}); })
setSuccess('Profil und Anzeigename erfolgreich aktualisiert!'); });
onUserUpdated(updatedUser); setSuccess('Profil und Anzeigename erfolgreich aktualisiert!');
if (onUserUpdated) onUserUpdated(updatedUser);
} else {
localStorage.setItem('guest_display_name', displayName.trim());
window.dispatchEvent(new Event('guest_name_updated'));
setSuccess('Gast-Name erfolgreich gespeichert!');
setTimeout(() => onClose(), 600);
}
} catch (err) { } catch (err) {
setError(err.message || 'Speichern des Profils fehlgeschlagen.'); setError(err.message || 'Speichern des Profils fehlgeschlagen.');
} finally { } finally {