From b0e727e4a50fd05370b2159ed2e4c85b52f95c31 Mon Sep 17 00:00:00 2001 From: Richard Date: Sat, 1 Aug 2026 12:35:48 +0200 Subject: [PATCH] fix: Redesign ProfileModal with Hallmark design tokens and safe array fallbacks --- frontend/dist/index.html | 4 +- frontend/src/components/ProfileModal.jsx | 185 ++++++++++++----------- 2 files changed, 101 insertions(+), 88 deletions(-) diff --git a/frontend/dist/index.html b/frontend/dist/index.html index b0ace1e..dbb7cdd 100644 --- a/frontend/dist/index.html +++ b/frontend/dist/index.html @@ -11,8 +11,8 @@ Schichtplaner — Veranstaltungsschichtpläne - - + +
diff --git a/frontend/src/components/ProfileModal.jsx b/frontend/src/components/ProfileModal.jsx index a8c91dd..61a65fd 100644 --- a/frontend/src/components/ProfileModal.jsx +++ b/frontend/src/components/ProfileModal.jsx @@ -1,14 +1,17 @@ import React, { useState } from 'react'; -import { X, User, Award, Check, AlertCircle } from 'lucide-react'; +import { X, User, Award, Check, AlertCircle, CheckCircle2 } from 'lucide-react'; import { apiFetch } from '../api/client'; import { getRandomSkillColor } from '../utils/colors'; -export default function ProfileModal({ user, skills, onClose, onUserUpdated, onRefreshSkills }) { +export default function ProfileModal({ user, skills = [], onClose, onUserUpdated, onRefreshSkills }) { + const safeSkills = Array.isArray(skills) ? skills : []; + const safeUserSkills = user?.skills ? (Array.isArray(user.skills) ? user.skills : []) : []; + const [displayName, setDisplayName] = useState( - user?.display_name || localStorage.getItem('guest_display_name') || '' + user?.display_name || user?.username || localStorage.getItem('guest_display_name') || '' ); const [selectedSkillIds, setSelectedSkillIds] = useState( - user?.skills ? user.skills.map(s => s.id) : [] + safeUserSkills.map(s => (typeof s === 'object' ? s.id : s)) ); // New skill fields @@ -38,6 +41,7 @@ export default function ProfileModal({ user, skills, onClose, onUserUpdated, onR }); setSuccess('Profil und Anzeigename erfolgreich aktualisiert!'); if (onUserUpdated) onUserUpdated(updatedUser); + setTimeout(() => onClose(), 800); } else { localStorage.setItem('guest_display_name', displayName.trim()); window.dispatchEvent(new Event('guest_name_updated')); @@ -79,7 +83,7 @@ export default function ProfileModal({ user, skills, onClose, onUserUpdated, onR setNewSkillDesc(''); setNewSkillColor(getRandomSkillColor()); setSuccess('Neue Fähigkeit erfolgreich angelegt!'); - onRefreshSkills(); + if (onRefreshSkills) onRefreshSkills(); } catch (err) { setError(err.message || 'Erstellen der Fähigkeit fehlgeschlagen.'); } finally { @@ -88,44 +92,51 @@ export default function ProfileModal({ user, skills, onClose, onUserUpdated, onR }; return ( -
-
+
+
+ {/* Close Button */} -
-
+ {/* Modal Header */} +
+
-

Profil & Einstellungen

-

Anzeigenamen und Qualifikationen verwalten

+

+ {user ? 'Profil & Qualifikationen' : 'Gast-Name anpassen'} +

+

+ {user ? 'Anzeigename & persönliche Qualifikationen verwalten' : 'Passe deinen Namen für Schichteintragungen an'} +

{error && ( -
+
{error}
)} {success && ( -
- +
+ {success}
)} -
+ {/* Display Name Edit Field */}
-
- {/* User Skills Selection */} -
- - {skills.length === 0 ? ( -

Noch keine Fähigkeiten definiert.

- ) : ( -
- {skills.map((s) => { - const isSelected = selectedSkillIds.includes(s.id); - return ( -
toggleSkill(s.id)} - className={`p-2.5 rounded-xl border cursor-pointer transition flex items-center justify-between ${ - isSelected - ? 'bg-slate-800 border-slate-700 text-white' - : 'bg-slate-950/60 border-slate-800/80 text-slate-400 hover:border-slate-700' - }`} - > -
- - {s.name} + {/* User Skills Selection (Only for logged-in users) */} + {user && ( +
+ + {safeSkills.length === 0 ? ( +

[ Noch keine Qualifikationen im System angelegt ]

+ ) : ( +
+ {safeSkills.map((s) => { + const isSelected = selectedSkillIds.includes(s.id); + return ( +
toggleSkill(s.id)} + className={`p-2.5 rounded-sm border cursor-pointer transition flex items-center justify-between font-mono ${ + isSelected + ? 'bg-surface-hover border-grid text-main font-bold shadow-sm' + : 'bg-subtle border-grid/60 text-muted hover:text-main hover:border-grid' + }`} + > +
+ + {s.name} +
+ {isSelected && }
- {isSelected && } -
- ); - })} -
- )} -
+ ); + })} +
+ )} +
+ )} -
+
- {/* Add New Skill Section */} -
-

- Neue Qualifikation im System anlegen -

-
- setNewSkillName(e.target.value)} - className="sm:col-span-2 px-3 py-2 rounded-xl bg-slate-950 border border-slate-800 text-white text-xs" - /> - setNewSkillColor(e.target.value)} - className="w-full h-8 rounded-xl border-0 cursor-pointer bg-slate-950 p-1" - /> -
-
- -
-
+ {/* Add New Skill Section (For Admins / Staff) */} + {user && (user.is_admin_user || user.is_staff || user.is_superuser) && ( +
+

+ Neue Qualifikation im System anlegen +

+
+ setNewSkillName(e.target.value)} + className="sm:col-span-7 px-3 py-2 rounded-sm bg-subtle border border-grid text-main text-xs font-sans" + /> + setNewSkillColor(e.target.value)} + className="sm:col-span-2 h-8 w-full rounded-sm border border-grid cursor-pointer bg-subtle p-0.5" + /> + +
+
+ )}
);