276 lines
12 KiB
TypeScript
276 lines
12 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import Link from "next/link";
|
|
import { Button, Input, Checkbox } from "@/components/ui";
|
|
import toast, { Toaster } from 'react-hot-toast';
|
|
import { saveAuth } from '@/lib/auth';
|
|
import { API_ENDPOINTS, apiRequest } from '@/lib/api';
|
|
import dynamic from 'next/dynamic';
|
|
|
|
const ThemeToggle = dynamic(() => import('@/components/ThemeToggle'), { ssr: false });
|
|
|
|
export default function LoginPage() {
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [formData, setFormData] = useState({
|
|
email: "",
|
|
password: "",
|
|
rememberMe: false,
|
|
});
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
|
|
// Validações básicas
|
|
if (!formData.email) {
|
|
toast.error('Por favor, insira seu email');
|
|
return;
|
|
}
|
|
|
|
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
|
|
toast.error('Por favor, insira um email válido');
|
|
return;
|
|
}
|
|
|
|
if (!formData.password) {
|
|
toast.error('Por favor, insira sua senha');
|
|
return;
|
|
}
|
|
|
|
setIsLoading(true);
|
|
|
|
try {
|
|
const response = await fetch('http://localhost:3000/api/auth/login', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
email: formData.email,
|
|
password: formData.password,
|
|
}),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const error = await response.json();
|
|
throw new Error(error.message || 'Credenciais inválidas');
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
// Salvar token e dados do usuário
|
|
localStorage.setItem('token', data.token);
|
|
localStorage.setItem('user', JSON.stringify(data.user));
|
|
|
|
toast.success('Login realizado com sucesso! Redirecionando...');
|
|
|
|
setTimeout(() => {
|
|
window.location.href = '/painel';
|
|
}, 1000);
|
|
} catch (error: any) {
|
|
toast.error(error.message || 'Erro ao fazer login. Verifique suas credenciais.');
|
|
setIsLoading(false);
|
|
}
|
|
}; return (
|
|
<>
|
|
<Toaster
|
|
position="top-center"
|
|
toastOptions={{
|
|
duration: 5000,
|
|
style: {
|
|
background: '#FFFFFF',
|
|
color: '#000000',
|
|
padding: '16px',
|
|
borderRadius: '8px',
|
|
border: '1px solid #E5E5E5',
|
|
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',
|
|
},
|
|
error: {
|
|
icon: '⚠️',
|
|
style: {
|
|
background: '#ff3a05',
|
|
color: '#FFFFFF',
|
|
border: 'none',
|
|
},
|
|
},
|
|
success: {
|
|
icon: '✓',
|
|
style: {
|
|
background: '#10B981',
|
|
color: '#FFFFFF',
|
|
border: 'none',
|
|
},
|
|
},
|
|
}}
|
|
/>
|
|
<div className="flex min-h-screen">
|
|
{/* Lado Esquerdo - Formulário */}
|
|
<div className="w-full lg:w-1/2 flex items-center justify-center px-6 sm:px-12 py-12">
|
|
<div className="w-full max-w-md">
|
|
{/* Logo mobile */}
|
|
<div className="lg:hidden text-center mb-8">
|
|
<div className="inline-block px-6 py-3 rounded-2xl bg-linear-to-r from-[#FF3A05] to-[#FF0080]">
|
|
<h1 className="text-3xl font-bold text-white">aggios</h1>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Theme Toggle */}
|
|
<div className="flex justify-end mb-4">
|
|
<ThemeToggle />
|
|
</div>
|
|
|
|
{/* Header */}
|
|
<div className="mb-8">
|
|
<h2 className="text-[28px] font-bold text-[#000000] dark:text-white">
|
|
Bem-vindo de volta
|
|
</h2>
|
|
<p className="text-[14px] text-[#7D7D7D] dark:text-gray-400 mt-2">
|
|
Entre com suas credenciais para acessar o painel
|
|
</p>
|
|
</div>
|
|
|
|
{/* Form */}
|
|
<form onSubmit={handleSubmit} className="space-y-5">
|
|
<Input
|
|
label="Email"
|
|
type="email"
|
|
placeholder="seu@email.com"
|
|
leftIcon="ri-mail-line"
|
|
value={formData.email}
|
|
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
|
|
required
|
|
/>
|
|
|
|
<Input
|
|
label="Senha"
|
|
type="password"
|
|
placeholder="Digite sua senha"
|
|
leftIcon="ri-lock-line"
|
|
value={formData.password}
|
|
onChange={(e) =>
|
|
setFormData({ ...formData, password: e.target.value })
|
|
}
|
|
required
|
|
/>
|
|
|
|
<div className="flex items-center justify-between">
|
|
<Checkbox
|
|
label="Lembrar de mim"
|
|
checked={formData.rememberMe}
|
|
onChange={(e) =>
|
|
setFormData({ ...formData, rememberMe: e.target.checked })
|
|
}
|
|
/>
|
|
<Link
|
|
href="/recuperar-senha"
|
|
className="text-[14px] gradient-text hover:underline font-medium cursor-pointer"
|
|
>
|
|
Esqueceu a senha?
|
|
</Link>
|
|
</div>
|
|
|
|
<Button
|
|
type="submit"
|
|
variant="primary"
|
|
className="w-full"
|
|
size="lg"
|
|
isLoading={isLoading}
|
|
>
|
|
Entrar
|
|
</Button>
|
|
</form>
|
|
|
|
{/* Divider */}
|
|
<div className="relative my-8">
|
|
<div className="absolute inset-0 flex items-center">
|
|
<div className="w-full border-t border-[#E5E5E5]" />
|
|
</div>
|
|
<div className="relative flex justify-center text-[13px]">
|
|
<span className="px-4 bg-white text-[#7D7D7D]">
|
|
ou continue com
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Social Login */}
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<Button variant="outline" leftIcon="ri-google-fill">
|
|
Google
|
|
</Button>
|
|
<Button variant="outline" leftIcon="ri-microsoft-fill">
|
|
Microsoft
|
|
</Button>
|
|
</div>
|
|
|
|
{/* Sign up link */}
|
|
<p className="text-center mt-8 text-[14px] text-[#7D7D7D]">
|
|
Não tem uma conta?{" "}
|
|
<Link href="/cadastro" className="gradient-text font-medium hover:underline cursor-pointer">
|
|
Criar conta
|
|
</Link>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Lado Direito - Branding */}
|
|
<div className="hidden lg:flex lg:w-1/2 relative overflow-hidden" style={{ background: 'linear-gradient(90deg, #FF3A05, #FF0080)' }}>
|
|
<div className="relative z-10 flex flex-col justify-center items-center w-full p-12 text-white">
|
|
{/* Logo */}
|
|
<div className="mb-8">
|
|
<div className="inline-block px-6 py-3 rounded-2xl bg-white/10 backdrop-blur-sm border border-white/20">
|
|
<h1 className="text-5xl font-bold tracking-tight bg-linear-to-r from-white to-white/80 bg-clip-text text-transparent">
|
|
aggios
|
|
</h1>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Conteúdo */}
|
|
<div className="max-w-lg text-center">
|
|
<div className="w-20 h-20 rounded-2xl bg-white/20 flex items-center justify-center mb-6 mx-auto">
|
|
<i className="ri-dashboard-line text-4xl" />
|
|
</div>
|
|
<h2 className="text-4xl font-bold mb-4">Gerencie seus projetos com facilidade</h2>
|
|
<p className="text-white/80 text-lg mb-8">
|
|
Tenha controle total sobre seus projetos, equipe e clientes em um só lugar.
|
|
</p>
|
|
|
|
{/* Features */}
|
|
<div className="space-y-4 text-left">
|
|
<div className="flex items-start gap-3">
|
|
<div className="w-6 h-6 rounded-full bg-white/20 flex items-center justify-center shrink-0 mt-0.5">
|
|
<i className="ri-shield-check-line text-sm" />
|
|
</div>
|
|
<div>
|
|
<h4 className="font-semibold mb-1">Gestão Completa</h4>
|
|
<p className="text-white/70 text-sm">Controle projetos, tarefas e prazos em tempo real</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-start gap-3">
|
|
<div className="w-6 h-6 rounded-full bg-white/20 flex items-center justify-center shrink-0 mt-0.5">
|
|
<i className="ri-check-line text-sm" />
|
|
</div>
|
|
<div>
|
|
<h4 className="font-semibold mb-1">Relatórios Detalhados</h4>
|
|
<p className="text-white/70 text-sm">Análises e métricas para tomada de decisão</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-start gap-3">
|
|
<div className="w-6 h-6 rounded-full bg-white/20 flex items-center justify-center shrink-0 mt-0.5">
|
|
<i className="ri-check-line text-sm" />
|
|
</div>
|
|
<div>
|
|
<h4 className="font-semibold mb-1">Colaboração em Equipe</h4>
|
|
<p className="text-white/70 text-sm">Trabalhe junto com sua equipe de forma eficiente</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Círculos decorativos */}
|
|
<div className="absolute top-0 right-0 w-96 h-96 bg-white/5 rounded-full blur-3xl" />
|
|
<div className="absolute bottom-0 left-0 w-96 h-96 bg-white/5 rounded-full blur-3xl" />
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|