- Tradução de rotas para português (entrar, cadastro, configuracoes, etc) - Ajuste de responsividade na página Financeiro (mobile) - Correção navegação Configurações para usuário CEO/Business Owner - Modal de gerenciamento de equipe com lista de profissionais - Exibição de fotógrafos, cinegrafistas e recepcionistas disponíveis por data - Ajuste de layout da logo nas telas de login e cadastro - Correção de z-index do header - Melhoria de espaçamento e padding em cards
160 lines
7.4 KiB
TypeScript
160 lines
7.4 KiB
TypeScript
|
|
import React, { useState } from 'react';
|
|
import { useAuth } from '../contexts/AuthContext';
|
|
import { Button } from '../components/Button';
|
|
import { Input } from '../components/Input';
|
|
import { UserRole } from '../types';
|
|
|
|
interface LoginProps {
|
|
onNavigate?: (page: string) => void;
|
|
}
|
|
|
|
export const Login: React.FC<LoginProps> = ({ onNavigate }) => {
|
|
const { login, availableUsers } = useAuth();
|
|
const [email, setEmail] = useState('');
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [error, setError] = useState('');
|
|
|
|
const handleLogin = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
setIsLoading(true);
|
|
setError('');
|
|
|
|
const success = await login(email);
|
|
if (!success) {
|
|
setError('Usuário não encontrado. Tente um dos e-mails de demonstração.');
|
|
}
|
|
setIsLoading(false);
|
|
};
|
|
|
|
const fillCredentials = (userEmail: string) => {
|
|
setEmail(userEmail);
|
|
};
|
|
|
|
const getRoleLabel = (role: UserRole) => {
|
|
switch (role) {
|
|
case UserRole.SUPERADMIN: return "Superadmin";
|
|
case UserRole.BUSINESS_OWNER: return "Empresa";
|
|
case UserRole.PHOTOGRAPHER: return "Fotógrafo";
|
|
case UserRole.EVENT_OWNER: return "Cliente";
|
|
default: return role;
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-gray-50 to-white p-4 pt-24">
|
|
<div className="w-full max-w-md fade-in relative z-10 space-y-6">
|
|
<div className="bg-white rounded-2xl shadow-xl border border-gray-100 p-6 sm:p-8">
|
|
{/* Logo dentro do card */}
|
|
<div className="flex justify-center mb-4">
|
|
<img
|
|
src="/logo.png"
|
|
alt="Photum Formaturas"
|
|
className="h-18 sm:h-30 w-auto max-w-[200px] object-contain"
|
|
/>
|
|
</div>
|
|
|
|
<div className="text-center">
|
|
<span className="font-bold tracking-widest uppercase text-xs sm:text-sm" style={{ color: '#B9CF33' }}>Bem-vindo de volta</span>
|
|
<h2 className="mt-2 text-2xl sm:text-3xl font-serif font-bold text-gray-900">Acesse sua conta</h2>
|
|
<p className="mt-2 text-xs sm:text-sm text-gray-600">
|
|
Não tem uma conta?{' '}
|
|
<button
|
|
type="button"
|
|
onClick={() => onNavigate?.('cadastro')}
|
|
className="font-medium hover:opacity-80 transition-opacity"
|
|
style={{ color: '#B9CF33' }}
|
|
>
|
|
Cadastre-se
|
|
</button>
|
|
</p>
|
|
</div>
|
|
|
|
<form className="mt-6 sm:mt-8 space-y-4 sm:space-y-6" onSubmit={handleLogin}>
|
|
<div className="space-y-3 sm:space-y-4">
|
|
<div>
|
|
<label className="block text-xs sm:text-sm font-medium text-gray-700 mb-1.5 sm:mb-2">
|
|
E-MAIL CORPORATIVO OU PESSOAL
|
|
</label>
|
|
<input
|
|
type="email"
|
|
required
|
|
placeholder="nome@exemplo.com"
|
|
value={email}
|
|
onChange={(e) => setEmail(e.target.value)}
|
|
className="w-full px-3 sm:px-4 py-2.5 sm:py-3 text-sm sm:text-base border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:border-transparent transition-all"
|
|
style={{ focusRing: '2px solid #B9CF33' }}
|
|
onFocus={(e) => e.target.style.borderColor = '#B9CF33'}
|
|
onBlur={(e) => e.target.style.borderColor = '#d1d5db'}
|
|
/>
|
|
{error && <span className="text-xs text-red-500 mt-1 block">{error}</span>}
|
|
</div>
|
|
<div>
|
|
<label className="block text-xs sm:text-sm font-medium text-gray-700 mb-1.5 sm:mb-2">
|
|
SENHA
|
|
</label>
|
|
<div className="relative">
|
|
<input
|
|
type="password"
|
|
placeholder="••••••••"
|
|
readOnly
|
|
className="w-full px-3 sm:px-4 py-2.5 sm:py-3 text-sm sm:text-base border border-gray-300 rounded-lg bg-gray-50 cursor-not-allowed"
|
|
/>
|
|
<button type="button" className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400">
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<button
|
|
type="submit"
|
|
disabled={isLoading}
|
|
className="w-full px-6 sm:px-10 py-3 sm:py-4 text-white font-bold text-base sm:text-lg rounded-lg transition-all duration-300 transform hover:scale-[1.02] hover:shadow-xl active:scale-95 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
style={{ backgroundColor: '#4E345F' }}
|
|
>
|
|
{isLoading ? 'Entrando...' : 'Entrar no Sistema'}
|
|
</button>
|
|
</form>
|
|
</div>
|
|
|
|
{/* Demo Users Quick Select */}
|
|
<div className="bg-white rounded-2xl shadow-xl border border-gray-100 p-6">
|
|
<p className="text-[10px] sm:text-xs uppercase tracking-widest mb-3 sm:mb-4 text-center text-gray-400">Usuários de Demonstração (Clique para preencher)</p>
|
|
<div className="space-y-2">
|
|
{availableUsers.map(user => (
|
|
<button
|
|
key={user.id}
|
|
onClick={() => fillCredentials(user.email)}
|
|
className="w-full flex items-center justify-between p-3 sm:p-4 border-2 rounded-xl hover:bg-gray-50 transition-all duration-300 text-left group transform hover:scale-[1.01] active:scale-[0.99]"
|
|
style={{ borderColor: '#e5e7eb' }}
|
|
onMouseEnter={(e) => {
|
|
e.currentTarget.style.borderColor = '#B9CF33';
|
|
e.currentTarget.style.boxShadow = '0 4px 12px rgba(185, 207, 51, 0.15)';
|
|
}}
|
|
onMouseLeave={(e) => {
|
|
e.currentTarget.style.borderColor = '#e5e7eb';
|
|
e.currentTarget.style.boxShadow = 'none';
|
|
}}
|
|
>
|
|
<div className="flex-1 min-w-0">
|
|
<div className="flex items-center gap-2 mb-1">
|
|
<span className="text-sm sm:text-base font-bold text-gray-900 truncate">{user.name}</span>
|
|
<span className="text-[10px] sm:text-xs uppercase tracking-wide font-semibold px-2 py-0.5 rounded-full whitespace-nowrap" style={{ backgroundColor: '#B9CF33', color: '#fff' }}>{getRoleLabel(user.role)}</span>
|
|
</div>
|
|
<span className="text-xs sm:text-sm text-gray-500 truncate block">{user.email}</span>
|
|
</div>
|
|
<svg className="w-5 h-5 text-gray-400 group-hover:text-[#B9CF33] transition-colors flex-shrink-0 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
|
</svg>
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|