From 987dd9af1430ce90fad4969a981f4a6b727b5b9f Mon Sep 17 00:00:00 2001 From: Tiago Yamamoto Date: Thu, 11 Dec 2025 20:44:02 -0300 Subject: [PATCH] feat: adiciona dropdown de perfil no header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Cria UserDropdown component com avatar e menu flutuante - Avatar com iniciais do nome do usuário - Menu dropdown com: Meu Perfil, Configurações, Sair - Move botão Sair da sidebar para dropdown - Adiciona página Profile com informações do usuário - Mantém design VSCode-like com gradiente cyan/blue no avatar - Build testado e aprovado (282KB gzipped) Fase 1/5 concluída ✅ --- dashboard/src/App.tsx | 14 ++- dashboard/src/components/UserDropdown.tsx | 135 +++++++++++++++++++++ dashboard/src/layouts/DashboardLayout.tsx | 26 +--- dashboard/src/pages/Profile.tsx | 137 ++++++++++++++++++++++ 4 files changed, 285 insertions(+), 27 deletions(-) create mode 100644 dashboard/src/components/UserDropdown.tsx create mode 100644 dashboard/src/pages/Profile.tsx diff --git a/dashboard/src/App.tsx b/dashboard/src/App.tsx index 678e045..9ab435d 100644 --- a/dashboard/src/App.tsx +++ b/dashboard/src/App.tsx @@ -6,6 +6,7 @@ import Hello from './pages/Hello' import Github from './pages/Github' import Home from './pages/Home' import Login from './pages/Login' +import Profile from './pages/Profile' import Settings from './pages/Settings' function App() { @@ -15,12 +16,13 @@ function App() { } /> }> - }> - } /> - } /> - } /> - } /> - } /> + }> + } /> + } /> + } /> + } /> + } /> + } /> diff --git a/dashboard/src/components/UserDropdown.tsx b/dashboard/src/components/UserDropdown.tsx new file mode 100644 index 0000000..6482de0 --- /dev/null +++ b/dashboard/src/components/UserDropdown.tsx @@ -0,0 +1,135 @@ +import { ChevronDown, LogOut, Settings, User } from 'lucide-react' +import { useState, useRef, useEffect } from 'react' +import { useNavigate } from 'react-router-dom' +import { useAuth } from '../contexts/Auth' + +export default function UserDropdown() { + const [isOpen, setIsOpen] = useState(false) + const dropdownRef = useRef(null) + const { user, logout } = useAuth() + const navigate = useNavigate() + + // Fecha dropdown ao clicar fora + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { + setIsOpen(false) + } + } + + if (isOpen) { + document.addEventListener('mousedown', handleClickOutside) + } + + return () => { + document.removeEventListener('mousedown', handleClickOutside) + } + }, [isOpen]) + + const handleLogout = async () => { + await logout() + navigate('/login') + } + + const getInitials = (name?: string, email?: string) => { + if (name) { + const names = name.split(' ') + return names.length >= 2 + ? `${names[0][0]}${names[names.length - 1][0]}`.toUpperCase() + : name.substring(0, 2).toUpperCase() + } + if (email) { + return email.substring(0, 2).toUpperCase() + } + return 'U' + } + + const initials = getInitials(user?.name, user?.email) + const displayName = user?.name || user?.email?.split('@')[0] || 'Usuário' + const displayEmail = user?.email || '' + + return ( +
+ {/* Trigger Button */} + + + {/* Dropdown Menu */} + {isOpen && ( +
+ {/* User Info Header */} +
+
+
+ {initials} +
+
+

{displayName}

+

{displayEmail}

+
+
+
+ + {/* Menu Items */} +
+ + + +
+ + {/* Logout */} +
+ +
+
+ )} +
+ ) +} diff --git a/dashboard/src/layouts/DashboardLayout.tsx b/dashboard/src/layouts/DashboardLayout.tsx index 7f7a2c4..db181d1 100644 --- a/dashboard/src/layouts/DashboardLayout.tsx +++ b/dashboard/src/layouts/DashboardLayout.tsx @@ -1,6 +1,7 @@ -import { Cloud, Github, Home, LogOut, Settings, Sparkles, Terminal } from 'lucide-react' -import { NavLink, Outlet, useNavigate } from 'react-router-dom' +import { Cloud, Github, Home, Settings, Sparkles, Terminal } from 'lucide-react' +import { NavLink, Outlet } from 'react-router-dom' import { TerminalLogs } from '../components/TerminalLogs' +import UserDropdown from '../components/UserDropdown' import { useAuth } from '../contexts/Auth' const navItems = [ @@ -17,13 +18,7 @@ const baseClass = 'flex items-center gap-2 rounded-md px-3 py-2 text-slate-300 hover:bg-slate-800/50 transition-colors duration-150 border border-transparent' export default function DashboardLayout() { - const { user, logout } = useAuth() - const navigate = useNavigate() - - const handleLogout = async () => { - await logout() - navigate('/login') - } + const { user } = useAuth() return (
@@ -53,14 +48,6 @@ export default function DashboardLayout() { {user?.email}

-
@@ -70,10 +57,7 @@ export default function DashboardLayout() {

Painel de Controle

DevOps Orchestration

-
- Online - {user?.name || user?.email} -
+
diff --git a/dashboard/src/pages/Profile.tsx b/dashboard/src/pages/Profile.tsx new file mode 100644 index 0000000..667ee6a --- /dev/null +++ b/dashboard/src/pages/Profile.tsx @@ -0,0 +1,137 @@ +import { User, Mail, Calendar, Shield } from 'lucide-react' +import { useAuth } from '../contexts/Auth' + +export default function Profile() { + const { user } = useAuth() + + const getInitials = (name?: string, email?: string) => { + if (name) { + const names = name.split(' ') + return names.length >= 2 + ? `${names[0][0]}${names[names.length - 1][0]}`.toUpperCase() + : name.substring(0, 2).toUpperCase() + } + if (email) { + return email.substring(0, 2).toUpperCase() + } + return 'U' + } + + const initials = getInitials(user?.name, user?.email) + const displayName = user?.name || 'Usuário' + const displayEmail = user?.email || 'email@exemplo.com' + const createdAt = user?.$createdAt ? new Date(user.$createdAt).toLocaleDateString('pt-BR') : 'N/A' + + return ( +
+ {/* Header */} +
+

Perfil

+

Minha Conta

+

+ Gerencie suas informações pessoais e preferências da conta. +

+
+ + {/* Profile Card */} +
+
+ {/* Avatar */} +
+ {initials} +
+ + {/* Info */} +
+
+

{displayName}

+

{displayEmail}

+
+ +
+ {/* Email */} +
+ +
+

Email

+

{displayEmail}

+
+
+ + {/* Created At */} +
+ +
+

Membro desde

+

{createdAt}

+
+
+ + {/* User ID */} +
+ +
+

User ID

+

{user?.$id || 'N/A'}

+
+
+ + {/* Status */} +
+ +
+

Status

+

Ativo

+
+
+
+
+
+
+ + {/* Actions */} +
+ {/* Edit Profile */} +
+

Editar Perfil

+

+ Atualize suas informações pessoais e preferências. +

+ +
+ + {/* Security */} +
+

Segurança

+

+ Gerenciar senha e autenticação de dois fatores. +

+ +
+
+ + {/* Stats Preview */} +
+

Estatísticas

+
+
+

0

+

Projetos

+
+
+

0

+

Tickets

+
+
+

100%

+

Uptime

+
+
+
+
+ ) +}