feat(freight:auth): show real user profile in top bar and fix logout

- DashboardLayout now accepts userName, userEmail, userInitials, onLogout
  props; computes initials from name; replaces hardcoded "John Doe" values
- Portal App.tsx pulls display name and email from useAuth user object and
  passes them to DashboardLayout
- handleLogout performs unconditional local cleanup (cookies + localStorage
  + hard redirect to /auth) so a failed API call never leaves the user stuck
- main.tsx purges cookies whose value is the literal string "undefined",
  clearing stale tokens written before the envelope interceptor fix

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Michael Abebe
2026-05-18 11:52:03 +03:00
parent 07c7b70cd0
commit 2478b0278b
3 changed files with 68 additions and 15 deletions

View File

@@ -17,6 +17,10 @@ export interface DashboardLayoutProps {
onNavigate?: (href: string) => void;
headerRight?: ReactNode;
enableThemeToggle?: boolean;
userName?: string;
userEmail?: string;
userInitials?: string;
onLogout?: () => void;
children: ReactNode;
}
@@ -42,8 +46,20 @@ const DashboardLayout = ({
onNavigate,
headerRight,
enableThemeToggle = false,
userName = "User",
userEmail,
userInitials,
onLogout,
children,
}: DashboardLayoutProps) => {
const initials =
userInitials ??
userName
.split(" ")
.filter(Boolean)
.slice(0, 2)
.map((n) => n[0].toUpperCase())
.join("");
const [theme, setTheme] = useState<Theme>(() =>
enableThemeToggle ? getInitialTheme() : "light",
);
@@ -148,10 +164,10 @@ const DashboardLayout = ({
className="flex items-center gap-2 rounded-xl border border-transparent px-2 py-1.5 transition hover:border-[#33578D]/20 hover:bg-[#33578D]/5 aria-expanded:border-[#33578D]/30 aria-expanded:bg-[#33578D]/10 dark:hover:border-[#33578D]/30 dark:hover:bg-[#33578D]/10 dark:aria-expanded:border-[#33578D]/40 dark:aria-expanded:bg-[#33578D]/20"
>
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-[#33578D] text-xs font-semibold text-white">
JD
{initials}
</div>
<span className="hidden text-sm font-medium text-slate-700 md:block dark:text-slate-200">
John Doe
{userName}
</span>
<ChevronDown
className={`h-4 w-4 text-slate-400 transition dark:text-slate-500 ${
@@ -167,11 +183,13 @@ const DashboardLayout = ({
>
<div className="border-b border-slate-100 px-4 py-3 dark:border-slate-700">
<p className="text-sm font-semibold text-slate-900 dark:text-slate-100">
John Doe
</p>
<p className="text-xs text-slate-500 dark:text-slate-400">
john.doe@edr.com
{userName}
</p>
{userEmail ? (
<p className="text-xs text-slate-500 dark:text-slate-400">
{userEmail}
</p>
) : null}
</div>
<a
href="#profile"
@@ -182,15 +200,18 @@ const DashboardLayout = ({
<User className="h-4 w-4" />
Profile
</a>
<a
href="#logout"
<button
type="button"
role="menuitem"
onClick={() => setIsUserMenuOpen(false)}
className="flex items-center gap-2 px-4 py-2 text-sm text-red-600 transition hover:bg-red-50 dark:text-red-400 dark:hover:bg-red-950/30"
onClick={() => {
setIsUserMenuOpen(false);
onLogout?.();
}}
className="flex w-full items-center gap-2 px-4 py-2 text-sm text-red-600 transition hover:bg-red-50 dark:text-red-400 dark:hover:bg-red-950/30"
>
<LogOut className="h-4 w-4" />
Logout
</a>
</button>
</div>
) : null}
</div>