// Caminho: components/LoginForm.tsx "use client" import type React from "react" import { useState } from "react" import { useRouter } from "next/navigation" import Link from "next/link" import Cookies from "js-cookie" import { jwtDecode } from "jwt-decode" import { cn } from "@/lib/utils" // Componentes Shadcn UI import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Separator } from "@/components/ui/separator" // Hook customizado import { useToast } from "@/hooks/use-toast" // Ícones import { Eye, EyeOff, Mail, Lock, Loader2, UserCheck, Stethoscope, IdCard, Receipt } from "lucide-react" interface LoginFormProps { title: string description: string role: "secretary" | "doctor" | "patient" | "admin" | "manager" | "finance" themeColor: "blue" | "green" | "orange" redirectPath: string children?: React.ReactNode } interface FormState { email: string password: string } // Supondo que o payload do seu token tenha esta estrutura interface DecodedToken { name: string email: string role: string exp: number // Adicione outros campos que seu token possa ter } const themeClasses = { blue: { iconBg: "bg-blue-100", iconText: "text-blue-600", button: "bg-blue-600 hover:bg-blue-700", link: "text-blue-600 hover:text-blue-700", focus: "focus:border-blue-500 focus:ring-blue-500", }, green: { iconBg: "bg-green-100", iconText: "text-green-600", button: "bg-green-600 hover:bg-green-700", link: "text-green-600 hover:text-green-700", focus: "focus:border-green-500 focus:ring-green-500", }, orange: { iconBg: "bg-orange-100", iconText: "text-orange-600", button: "bg-orange-600 hover:bg-orange-700", link: "text-orange-600 hover:text-orange-700", focus: "focus:border-orange-500 focus:ring-orange-500", }, } const roleIcons = { secretary: UserCheck, patient: Stethoscope, doctor: Stethoscope, admin: UserCheck, manager: IdCard, finance: Receipt, } export function LoginForm({ title, description, role, themeColor, redirectPath, children }: LoginFormProps) { const [form, setForm] = useState({ email: "", password: "" }) const [showPassword, setShowPassword] = useState(false) const [isLoading, setIsLoading] = useState(false) const router = useRouter() const { toast } = useToast() const currentTheme = themeClasses[themeColor] const Icon = roleIcons[role] // ================================================================== // AJUSTE PRINCIPAL NA LÓGICA DE LOGIN // ================================================================== const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setIsLoading(true); const LOGIN_URL = "https://yuanqfswhberkoevtmfr.supabase.co/auth/v1/token?grant_type=password"; const API_KEY = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY; if (!API_KEY) { toast({ title: "Erro de Configuração", description: "A chave da API não foi encontrada.", variant: "destructive", }); setIsLoading(false); return; } try { const response = await fetch(LOGIN_URL, { method: "POST", headers: { "Content-Type": "application/json", "apikey": API_KEY, }, body: JSON.stringify({ email: form.email, password: form.password }), }); const data = await response.json(); if (!response.ok) { throw new Error(data.error_description || "Credenciais inválidas. Tente novamente."); } const accessToken = data.access_token; const user = data.user; /* =================== Verificação de Role Desativada Temporariamente =================== */ // if (user.user_metadata.role !== role) { // toast({ title: "Acesso Negado", ... }); // return; // } /* ===================================================================================== */ Cookies.set("access_token", accessToken, { expires: 1, secure: true }); localStorage.setItem('user_info', JSON.stringify(user)); toast({ title: "Login bem-sucedido!", description: `Bem-vindo(a), ${user.user_metadata.full_name || 'usuário'}! Redirecionando...`, }); router.push(redirectPath); } catch (error) { toast({ title: "Erro no Login", description: error instanceof Error ? error.message : "Ocorreu um erro inesperado.", }); } finally { setIsLoading(false); } }; // O JSX do return permanece exatamente o mesmo, preservando seus ajustes. return (
{title} {description}
{/* Inputs e Botão */}
setForm({ ...form, email: e.target.value })} className={cn("pl-11 h-12 border-slate-200", currentTheme.focus)} required disabled={isLoading} />
setForm({ ...form, password: e.target.value })} className={cn("pl-11 pr-12 h-12 border-slate-200", currentTheme.focus)} required disabled={isLoading} />
{/* Conteúdo Extra (children) */}
{children ? (
Novo por aqui?
{children}
) : ( <>
ou
Voltar à página inicial
)}
) }