From 7430ae15a88ffdb80e2cb9f0dfd087c0e04fb64a Mon Sep 17 00:00:00 2001 From: Lucas Santana Date: Fri, 20 Dec 2024 13:45:29 -0300 Subject: [PATCH] feat: adiciona menu de perfil no header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Cria componente ProfileMenu com dropdown - Implementa navegação contextual baseada no role do usuário - Adiciona opções de acesso ao dashboard, perfil e logout - Atualiza Header para mostrar/esconder botões baseado no estado de autenticação - Adiciona detecção de clique fora do menu para fechá-lo --- src/components/header/Header.tsx | 42 ++++++++ src/components/header/ProfileMenu.tsx | 98 +++++++++++++++++++ src/hooks/useAuth.tsx | 3 + src/pages/admin/UserManagementPage.tsx | 2 +- src/pages/student-dashboard/StoryPage.tsx | 2 + .../StudentDashboardPage.tsx | 8 +- src/types/database.ts | 13 +++ 7 files changed, 163 insertions(+), 5 deletions(-) create mode 100644 src/components/header/Header.tsx create mode 100644 src/components/header/ProfileMenu.tsx diff --git a/src/components/header/Header.tsx b/src/components/header/Header.tsx new file mode 100644 index 0000000..d743452 --- /dev/null +++ b/src/components/header/Header.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { useAuth } from '../../hooks/useAuth'; +import { ProfileMenu } from './ProfileMenu'; + +export function Header() { + const { user } = useAuth(); + + return ( +
+
+
+ + Logo + Histórias Mágicas + + +
+ {user ? ( + + ) : ( + <> + + Entrar + + + Cadastrar Escola + + + )} +
+
+
+
+ ); +} \ No newline at end of file diff --git a/src/components/header/ProfileMenu.tsx b/src/components/header/ProfileMenu.tsx new file mode 100644 index 0000000..f607717 --- /dev/null +++ b/src/components/header/ProfileMenu.tsx @@ -0,0 +1,98 @@ +import React from 'react'; +import { useNavigate } from 'react-router-dom'; +import { LogOut, Settings, LayoutDashboard } from 'lucide-react'; +import { useAuth } from '../../hooks/useAuth'; + +export function ProfileMenu() { + const { user, userRole, signOut } = useAuth(); + const navigate = useNavigate(); + const [isOpen, setIsOpen] = React.useState(false); + const menuRef = React.useRef(null); + + // Fecha o menu quando clicar fora dele + React.useEffect(() => { + function handleClickOutside(event: MouseEvent) { + if (menuRef.current && !menuRef.current.contains(event.target as Node)) { + setIsOpen(false); + } + } + + document.addEventListener('mousedown', handleClickOutside); + return () => document.removeEventListener('mousedown', handleClickOutside); + }, []); + + const getDashboardPath = () => { + switch (userRole) { + case 'school': + return '/dashboard'; + case 'teacher': + return '/professor'; + case 'student': + return '/aluno'; + default: + return '/'; + } + }; + + const getProfilePath = () => { + switch (userRole) { + case 'school': + return '/dashboard/configuracoes'; + case 'teacher': + return '/professor/perfil'; + case 'student': + return '/aluno/perfil'; + default: + return '/'; + } + }; + + return ( +
+ + + {isOpen && ( +
+ + + + +
+ + +
+ )} +
+ ); +} \ No newline at end of file diff --git a/src/hooks/useAuth.tsx b/src/hooks/useAuth.tsx index 0ea4382..958f066 100644 --- a/src/hooks/useAuth.tsx +++ b/src/hooks/useAuth.tsx @@ -5,6 +5,9 @@ import { supabase } from '../lib/supabase'; interface AuthContextType { user: any; loading: boolean; + error: string | null; + signIn: (email: string, password: string) => Promise; + signUp: (email: string, password: string) => Promise; signOut: () => Promise; userRole: string | null; } diff --git a/src/pages/admin/UserManagementPage.tsx b/src/pages/admin/UserManagementPage.tsx index 1ffeb63..a0f70fd 100644 --- a/src/pages/admin/UserManagementPage.tsx +++ b/src/pages/admin/UserManagementPage.tsx @@ -23,7 +23,7 @@ export function UserManagementPage() { try { const { data: { users }, error } = await supabase.auth.admin.listUsers(); if (error) throw error; - setUsers(users || []); + setUsers(users?.filter(user => user.email) || []); } catch (err) { console.error('Erro ao buscar usuários:', err); setError('Não foi possível carregar os usuários'); diff --git a/src/pages/student-dashboard/StoryPage.tsx b/src/pages/student-dashboard/StoryPage.tsx index 2962cfc..0cb165a 100644 --- a/src/pages/student-dashboard/StoryPage.tsx +++ b/src/pages/student-dashboard/StoryPage.tsx @@ -129,6 +129,8 @@ export function StoryPage() { { console.log('Áudio gravado:', audioUrl); }} diff --git a/src/pages/student-dashboard/StudentDashboardPage.tsx b/src/pages/student-dashboard/StudentDashboardPage.tsx index be89c8a..0e5b604 100644 --- a/src/pages/student-dashboard/StudentDashboardPage.tsx +++ b/src/pages/student-dashboard/StudentDashboardPage.tsx @@ -117,8 +117,8 @@ export function StudentDashboardPage() { {student?.avatar_url ? ( {student?.name} ) : ( @@ -128,8 +128,8 @@ export function StudentDashboardPage() {

{student?.name}

-

- {(student?.class as any)?.grade} • {(student?.class as any)?.name} • {(student?.school as any)?.name} +

+ {student?.class?.name} - {student?.class?.grade} • {student?.school?.name}

diff --git a/src/types/database.ts b/src/types/database.ts index e304dc0..070c42e 100644 --- a/src/types/database.ts +++ b/src/types/database.ts @@ -33,6 +33,7 @@ export interface Class { export interface Student { id: string; class_id: string; + school_id: string; name: string; email: string; birth_date?: string; @@ -41,6 +42,18 @@ export interface Student { guardian_email?: string; created_at: string; updated_at: string; + status?: string; + avatar_url?: string; + // Relacionamentos + class?: { + id: string; + name: string; + grade: string; + }; + school?: { + id: string; + name: string; + }; } export interface TeacherClass {