-
-
setForm({ ...form, email: e.target.value })}
- className="pl-10 h-11"
- required
- disabled={isLoading}
- autoComplete="username" // Boa prática de acessibilidade
- />
+
+ {userRoles.length === 0 ? (
+ // VISÃO 1: Formulário de Login (se nenhum perfil foi carregado ainda)
+
+ ) : (
+ // VISÃO 2: Tela de Seleção de Perfil (se múltiplos perfis foram encontrados)
+
+
Você tem múltiplos perfis
+
Selecione com qual perfil deseja entrar:
+
+ {userRoles.map((role) => (
+ handleRoleSelection(role)}
+ >
+ Entrar como: {role.charAt(0).toUpperCase() + role.slice(1)}
+
+ ))}
-
-
Senha
-
-
- setForm({ ...form, password: e.target.value })}
- className="pl-10 pr-12 h-11"
- required
- disabled={isLoading}
- autoComplete="current-password" // Boa prática de acessibilidade
- />
- setShowPassword(!showPassword)} className="absolute right-2 top-1/2 -translate-y-1/2 h-8 w-8 p-0 text-muted-foreground hover:text-foreground" disabled={isLoading}>
- {showPassword ? : }
-
-
-
-
- {isLoading ? : "Entrar"}
-
-
+ )}
- {/* O children permite que a página de login adicione links extras aqui */}
{children}
diff --git a/components/doctor-layout.tsx b/components/doctor-layout.tsx
index 509af00..2dd2300 100644
--- a/components/doctor-layout.tsx
+++ b/components/doctor-layout.tsx
@@ -120,13 +120,13 @@ export default function DoctorLayout({ children }: PatientLayoutProps) {
// Botão para o dashboard do médico
},
{
- href: "/doctor/medicos/consultas",
+ href: "/doctor/consultas",
icon: Calendar,
label: "Consultas",
// Botão para página de consultas marcadas do médico atual
},
{
- href: "#",
+ href: "/doctor/medicos/editorlaudo",
icon: Clock,
label: "Editor de Laudo",
// Botão para página do editor de laudo
diff --git a/components/manager-layout.tsx b/components/manager-layout.tsx
index 2af8ac9..7c1e3fe 100644
--- a/components/manager-layout.tsx
+++ b/components/manager-layout.tsx
@@ -95,11 +95,11 @@ export default function ManagerLayout({ children }: ManagerLayoutProps) {
const cancelLogout = () => setShowLogoutDialog(false);
const menuItems = [
- { href: "#dashboard", icon: Home, label: "Dashboard" },
- { href: "#reports", icon: Calendar, label: "Relatórios gerenciais" },
- { href: "#users", icon: User, label: "Gestão de Usuários" },
- { href: "#doctors", icon: User, label: "Gestão de Médicos" },
- { href: "#settings", icon: Calendar, label: "Configurações" },
+ { href: "/manager/dashboard", icon: Home, label: "Dashboard" },
+ { href: "#", icon: Calendar, label: "Relatórios gerenciais" },
+ { href: "/manager/usuario", icon: User, label: "Gestão de Usuários" },
+ { href: "/manager/home", icon: User, label: "Gestão de Médicos" },
+ { href: "#", icon: Calendar, label: "Configurações" },
];
if (!managerData) {
diff --git a/hooks/useAuth.ts b/hooks/useAuth.ts
new file mode 100644
index 0000000..6d0059f
--- /dev/null
+++ b/hooks/useAuth.ts
@@ -0,0 +1,42 @@
+// Caminho: hooks/useAuth.ts
+import { useState, useEffect } from 'react';
+import { useRouter } from 'next/navigation';
+import Cookies from 'js-cookie';
+
+// Uma interface genérica para as informações do usuário que pegamos do localStorage
+interface UserInfo {
+ id: string;
+ email: string;
+ user_metadata: {
+ full_name?: string;
+ role?: string; // O perfil escolhido no login
+ specialty?: string;
+ department?: string;
+ };
+ // Adicione outros campos que possam existir
+}
+
+export function useAuth() {
+ const [user, setUser] = useState
(null);
+ const router = useRouter();
+
+ useEffect(() => {
+ const userInfoString = localStorage.getItem('user_info');
+ const token = Cookies.get('access_token');
+
+ if (userInfoString && token) {
+ try {
+ const userInfo = JSON.parse(userInfoString);
+ setUser(userInfo);
+ } catch (error) {
+ console.error("Erro ao parsear user_info do localStorage", error);
+ router.push('/'); // Redireciona se os dados estiverem corrompidos
+ }
+ } else {
+ // Se não houver token ou info, redireciona para a página inicial/login
+ router.push('/');
+ }
+ }, [router]);
+
+ return user; // Retorna o usuário logado ou null enquanto carrega/redireciona
+}
\ No newline at end of file
diff --git a/services/api.mjs b/services/api.mjs
index 548c86a..67a9002 100644
--- a/services/api.mjs
+++ b/services/api.mjs
@@ -1,65 +1,13 @@
-// Caminho: [seu-caminho]/services/api.mjs
+// Caminho: services/api.mjs
-const BASE_URL = "https://yuanqfswhberkoevtmfr.supabase.co";
-const API_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ";
+// As suas variáveis de ambiente já estão corretas no arquivo .env.local
+const BASE_URL = process.env.NEXT_PUBLIC_SUPABASE_URL;
+const API_KEY = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
-export async function loginWithEmailAndPassword(email, password) {
- const response = await fetch(`${BASE_URL}/auth/v1/token?grant_type=password`, {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- "apikey": API_KEY,
- },
- body: JSON.stringify({ email, password }),
- });
-
- const data = await response.json();
-
- if (!response.ok) {
- throw new Error(data.error_description || "Credenciais inválidas.");
- }
-
- if (data.access_token && typeof window !== 'undefined') {
- // Padronizando para salvar o token no localStorage
- localStorage.setItem("token", data.access_token);
- }
-
- return data;
-}
-
-// --- NOVA FUNÇÃO DE LOGOUT CENTRALIZADA ---
-async function logout() {
- const token = localStorage.getItem("token");
- if (!token) return; // Se não há token, não há o que fazer
-
- try {
- await fetch(`${BASE_URL}/auth/v1/logout`, {
- method: "POST",
- headers: {
- "apikey": API_KEY,
- "Authorization": `Bearer ${token}`,
- },
- });
- } catch (error) {
- // Mesmo que a chamada falhe, o logout no cliente deve continuar.
- // O token pode já ter expirado no servidor, por exemplo.
- console.error("Falha ao invalidar token no servidor (isso pode ser normal se o token já expirou):", error);
- }
-}
-
-async function request(endpoint, options = {}) {
- const token = typeof window !== 'undefined' ? localStorage.getItem("token") : null;
-
- const headers = {
- "Content-Type": "application/json",
- "apikey": API_KEY,
- ...(token ? { "Authorization": `Bearer ${token}` } : {}),
- ...options.headers,
- };
-const API_KEY =
- "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ";
-
-export const apikey = API_KEY;
+/**
+ * Função de login que o seu formulário vai chamar.
+ * Ela autentica e salva o token no localStorage.
+ */
let loginPromise = null;
export async function login() {
@@ -93,89 +41,68 @@ export async function login() {
return data;
}
-async function request(endpoint, options = {}) {
- if (!loginPromise) loginPromise = login();
+/**
+ * Função de logout que o seu DashboardLayout vai chamar.
+ */
+async function logout() {
+ const token = localStorage.getItem("token");
+ if (!token) return;
try {
- await loginPromise;
+ await fetch(`${BASE_URL}/auth/v1/logout`, {
+ method: "POST",
+ headers: {
+ "apikey": API_KEY,
+ "Authorization": `Bearer ${token}`,
+ },
+ });
} catch (error) {
- console.error("⚠️ Falha ao autenticar:", error);
+ console.error("Falha ao invalidar token no servidor (pode ser normal se o token já expirou):", error);
} finally {
- loginPromise = null;
+ // Limpa os dados do cliente independentemente do resultado do servidor
+ localStorage.removeItem("token");
+ localStorage.removeItem("user_info");
}
+}
- let token =
- typeof window !== "undefined" ? localStorage.getItem("token") : null;
-
- if (!token) {
- console.warn("⚠️ Token não encontrado, refazendo login...");
- const data = await login();
- token = data.access_token;
- }
+/**
+ * Função genérica e centralizada para fazer requisições autenticadas.
+ * Ela pega o token do localStorage automaticamente.
+ */
+async function request(endpoint, options = {}) {
+ const token = typeof window !== 'undefined' ? localStorage.getItem("token") : null;
const headers = {
"Content-Type": "application/json",
- apikey: API_KEY,
- Authorization: `Bearer ${token}`,
+ "apikey": API_KEY,
+ // Adiciona o cabeçalho de autorização apenas se o token existir
+ ...(token && { "Authorization": `Bearer ${token}` }),
...options.headers,
};
- const fullUrl =
- endpoint.startsWith("/rest/v1") || endpoint.startsWith("/functions/")
- ? `${BASE_URL}${endpoint}`
- : `${BASE_URL}/rest/v1${endpoint}`;
+ const response = await fetch(`${BASE_URL}${endpoint}`, { ...options, headers });
- console.log("🌐 Requisição para:", fullUrl, "com headers:", headers);
-
- const response = await fetch(fullUrl, {
- ...options,
- headers,
- });
-
- if (!response.ok) {
- let errorBody;
- try {
- errorBody = await response.json();
- } catch (e) {
- errorBody = await response.text();
- }
- throw new Error(`Erro HTTP: ${response.status} - ${JSON.stringify(errorBody)}`);
- }
-
- if (response.status === 204) return {};
- return await response.json();
-
- } catch (error) {
- console.error("Erro na requisição:", error);
- throw error;
- }
-}
-
-// Adicionamos a função de logout ao nosso objeto de API exportado
-export const api = {
- get: (endpoint, options) => request(endpoint, { method: "GET", ...options }),
- post: (endpoint, data, options) => request(endpoint, { method: "POST", body: JSON.stringify(data), ...options }),
- patch: (endpoint, data, options) => request(endpoint, { method: "PATCH", body: JSON.stringify(data), ...options }),
- delete: (endpoint, options) => request(endpoint, { method: "DELETE", ...options }),
- logout: logout, // <-- EXPORTANDO A NOVA FUNÇÃO
-};
if (!response.ok) {
- const msg = await response.text();
- console.error("❌ Erro HTTP:", response.status, msg);
- throw new Error(`Erro HTTP: ${response.status} - Detalhes: ${msg}`);
+ const errorBody = await response.json().catch(() => response.text());
+ console.error("Erro na requisição:", response.status, errorBody);
+ throw new Error(`Erro na API: ${errorBody.message || JSON.stringify(errorBody)}`);
}
- const contentType = response.headers.get("content-type");
- if (!contentType || !contentType.includes("application/json")) return {};
- return await response.json();
+ // Se a resposta for 204 No Content (como em um DELETE), não tenta fazer o parse do JSON
+ if (response.status === 204) {
+ return null;
+ }
+
+ return response.json();
}
+
+
+// Exportamos um objeto 'api' com os métodos que os componentes vão usar.
export const api = {
get: (endpoint, options) => request(endpoint, { method: "GET", ...options }),
- post: (endpoint, data) =>
- request(endpoint, { method: "POST", body: JSON.stringify(data) }),
- patch: (endpoint, data) =>
- request(endpoint, { method: "PATCH", body: JSON.stringify(data) }),
- delete: (endpoint) => request(endpoint, { method: "DELETE" }),
-};
-
+ post: (endpoint, data, options) => request(endpoint, { method: "POST", body: JSON.stringify(data), ...options }),
+ patch: (endpoint, data, options) => request(endpoint, { method: "PATCH", body: JSON.stringify(data), ...options }),
+ delete: (endpoint, options) => request(endpoint, { method: "DELETE", ...options }),
+ logout: logout, // Exportando a função de logout
+};
\ No newline at end of file
diff --git a/services/doctorsApi.mjs b/services/doctorsApi.mjs
index b2999f1..5d918a0 100644
--- a/services/doctorsApi.mjs
+++ b/services/doctorsApi.mjs
@@ -3,7 +3,7 @@ import { api } from "./api.mjs";
export const doctorsService = {
list: () => api.get("/rest/v1/doctors"),
getById: (id) => api.get(`/rest/v1/doctors?id=eq.${id}`).then(data => data[0]),
- create: (data) => api.post("/rest/v1/doctors", data),
+ create: (data) => api.post("/functions/v1/create-doctor", data),
update: (id, data) => api.patch(`/rest/v1/doctors?id=eq.${id}`, data),
delete: (id) => api.delete(`/rest/v1/doctors?id=eq.${id}`),
};
\ No newline at end of file
diff --git a/services/usersApi.mjs b/services/usersApi.mjs
index 263ada8..4749d59 100644
--- a/services/usersApi.mjs
+++ b/services/usersApi.mjs
@@ -8,7 +8,8 @@ export const usersService = {
async create_user(data) {
// continua usando a Edge Function corretamente
- return await api.post(`/functions/v1/user-create`, data);
+ return await api.post(`/functions/v1/create-user-with-password
+`, data);
},
// 🚀 Busca dados completos do usuário direto do banco
@@ -52,4 +53,4 @@ export const usersService = {
permissions,
};
},
-};
+};
\ No newline at end of file