From a8a2d5c09a05096374e49c84203033301d02798a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gustavo?= <166467972+JoaoGustavo-dev@users.noreply.github.com> Date: Sun, 21 Sep 2025 16:58:18 -0300 Subject: [PATCH] add login screen in doctors page --- susconecta/app/layout.tsx | 7 +- susconecta/app/login/page.tsx | 124 +++++++++++++++++++++++ susconecta/app/profissional/page.tsx | 47 ++++++--- susconecta/components/ProtectedRoute.tsx | 40 ++++++++ susconecta/hooks/useAuth.tsx | 90 ++++++++++++++++ 5 files changed, 292 insertions(+), 16 deletions(-) create mode 100644 susconecta/app/login/page.tsx create mode 100644 susconecta/components/ProtectedRoute.tsx create mode 100644 susconecta/hooks/useAuth.tsx diff --git a/susconecta/app/layout.tsx b/susconecta/app/layout.tsx index f127de6..52ed9d1 100644 --- a/susconecta/app/layout.tsx +++ b/susconecta/app/layout.tsx @@ -1,5 +1,6 @@ import type React from "react" import type { Metadata } from "next" +import { AuthProvider } from "@/hooks/useAuth" import "./globals.css" export const metadata: Metadata = { @@ -17,7 +18,11 @@ export default function RootLayout({ }) { return ( - {children} + + + {children} + + ) } diff --git a/susconecta/app/login/page.tsx b/susconecta/app/login/page.tsx new file mode 100644 index 0000000..e563c6d --- /dev/null +++ b/susconecta/app/login/page.tsx @@ -0,0 +1,124 @@ +'use client' +import { useState } from 'react' +import { useRouter } from 'next/navigation' +import Link from 'next/link' +import { useAuth } from '@/hooks/useAuth' +import { Button } from '@/components/ui/button' +import { Input } from '@/components/ui/input' +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' +import { Alert, AlertDescription } from '@/components/ui/alert' + +export default function LoginPage() { + const [credentials, setCredentials] = useState({ email: '', password: '' }) + const [error, setError] = useState('') + const [loading, setLoading] = useState(false) + const router = useRouter() + const { login } = useAuth() + + const handleLogin = async (e: React.FormEvent) => { + e.preventDefault() + setLoading(true) + setError('') + + // Simular delay de autenticação + await new Promise(resolve => setTimeout(resolve, 1000)) + + // Tentar fazer login usando o contexto + const success = login(credentials.email, credentials.password) + + if (success) { + // Aguardar um pouco para garantir que o estado foi atualizado + setTimeout(() => { + // Tentar router.push primeiro + router.push('/profissional') + + // Fallback: usar window.location se router.push não funcionar + setTimeout(() => { + if (window.location.pathname === '/login') { + window.location.href = '/profissional' + } + }, 100) + }, 100) + } else { + setError('Email ou senha incorretos') + } + + setLoading(false) + } + + return ( +
+
+
+

+ Login Profissional de Saúde +

+

+ Entre com suas credenciais para acessar o sistema +

+
+ + + + Acesso ao Sistema + + +
+
+ + setCredentials({...credentials, email: e.target.value})} + required + className="mt-1" + /> +
+ +
+ + setCredentials({...credentials, password: e.target.value})} + required + className="mt-1" + /> +
+ + {error && ( + + {error} + + )} + + +
+ +
+ +
+
+
+
+
+ ) +} \ No newline at end of file diff --git a/susconecta/app/profissional/page.tsx b/susconecta/app/profissional/page.tsx index d69ffda..76f070c 100644 --- a/susconecta/app/profissional/page.tsx +++ b/susconecta/app/profissional/page.tsx @@ -2,6 +2,8 @@ import React, { useState } from "react"; import Link from "next/link"; +import ProtectedRoute from "@/components/ProtectedRoute"; +import { useAuth } from "@/hooks/useAuth"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; @@ -65,6 +67,7 @@ const colorsByType = { }; const ProfissionalPage = () => { + const { logout, userEmail } = useAuth(); const [activeSection, setActiveSection] = useState('calendario'); const [pacienteSelecionado, setPacienteSelecionado] = useState(null); const [events, setEvents] = useState([ @@ -615,20 +618,33 @@ const ProfissionalPage = () => { }; return ( -
-
- - - - - - -
-

Conta do profissional

-

{medico.nome}

-

{medico.identificacao}

-
-
+ +
+
+
+ + + + + + +
+

Conta do profissional

+

{medico.nome}

+

{medico.identificacao}

+ {userEmail && ( +

Logado como: {userEmail}

+ )} +
+
+ +
{} @@ -851,7 +867,8 @@ const ProfissionalPage = () => {
)} -
+ + ); }; diff --git a/susconecta/components/ProtectedRoute.tsx b/susconecta/components/ProtectedRoute.tsx new file mode 100644 index 0000000..ae0d93a --- /dev/null +++ b/susconecta/components/ProtectedRoute.tsx @@ -0,0 +1,40 @@ +'use client' +import { useEffect } from 'react' +import { useRouter } from 'next/navigation' +import { useAuth } from '@/hooks/useAuth' + +interface ProtectedRouteProps { + children: React.ReactNode +} + +export default function ProtectedRoute({ children }: ProtectedRouteProps) { + const { isAuthenticated, checkAuth } = useAuth() + const router = useRouter() + + useEffect(() => { + // Verificar autenticação sempre que o componente montar + checkAuth() + }, [checkAuth]) + + useEffect(() => { + if (!isAuthenticated) { + console.log('Usuário não autenticado, redirecionando para login...') + router.push('/login') + } else { + console.log('Usuário autenticado!') + } + }, [isAuthenticated, router]) + + if (!isAuthenticated) { + return ( +
+
+
+

Redirecionando para login...

+
+
+ ) + } + + return <>{children} +} \ No newline at end of file diff --git a/susconecta/hooks/useAuth.tsx b/susconecta/hooks/useAuth.tsx new file mode 100644 index 0000000..c000fc8 --- /dev/null +++ b/susconecta/hooks/useAuth.tsx @@ -0,0 +1,90 @@ +'use client' +import { createContext, useContext, useEffect, useState, ReactNode } from 'react' +import { useRouter } from 'next/navigation' + +interface AuthContextType { + isAuthenticated: boolean + userEmail: string | null + login: (email: string, password: string) => boolean + logout: () => void + checkAuth: () => void +} + +const AuthContext = createContext(undefined) + +export function AuthProvider({ children }: { children: ReactNode }) { + const [isAuthenticated, setIsAuthenticated] = useState(false) + const [userEmail, setUserEmail] = useState(null) + const [isLoading, setIsLoading] = useState(true) + const router = useRouter() + + const checkAuth = () => { + if (typeof window !== 'undefined') { + const auth = localStorage.getItem('isAuthenticated') + const email = localStorage.getItem('userEmail') + + if (auth === 'true' && email) { + setIsAuthenticated(true) + setUserEmail(email) + } else { + setIsAuthenticated(false) + setUserEmail(null) + } + } + setIsLoading(false) + } + + useEffect(() => { + checkAuth() + }, []) + + const login = (email: string, password: string): boolean => { + if (email === 'teste@gmail.com' && password === '123456') { + localStorage.setItem('isAuthenticated', 'true') + localStorage.setItem('userEmail', email) + setIsAuthenticated(true) + setUserEmail(email) + return true + } + return false + } + + const logout = () => { + localStorage.removeItem('isAuthenticated') + localStorage.removeItem('userEmail') + setIsAuthenticated(false) + setUserEmail(null) + router.push('/login') + } + + if (isLoading) { + return ( +
+
+
+

Carregando...

+
+
+ ) + } + + return ( + + {children} + + ) +} + +export const useAuth = () => { + const context = useContext(AuthContext) + if (context === undefined) { + throw new Error('useAuth deve ser usado dentro de AuthProvider') + } + return context +} \ No newline at end of file -- 2.47.2