100 lines
3.3 KiB
TypeScript
100 lines
3.3 KiB
TypeScript
import { FormEvent, useState } from 'react'
|
|
import axios from 'axios'
|
|
import { useAuth, UserRole } from '../context/AuthContext'
|
|
import { authService } from '../services/auth'
|
|
import { decodeJwtPayload } from '../utils/jwt'
|
|
|
|
export function LoginPage() {
|
|
const { login } = useAuth()
|
|
const [username, setUsername] = useState('')
|
|
const [password, setPassword] = useState('')
|
|
const [errorMessage, setErrorMessage] = useState<string | null>(null)
|
|
const [loading, setLoading] = useState(false)
|
|
|
|
const resolveRole = (role?: string): UserRole => {
|
|
switch (role?.toLowerCase()) {
|
|
case 'admin':
|
|
return 'admin'
|
|
case 'customer':
|
|
return 'customer'
|
|
case 'seller':
|
|
default:
|
|
return 'seller'
|
|
}
|
|
}
|
|
|
|
const onSubmit = async (event: FormEvent) => {
|
|
event.preventDefault()
|
|
setLoading(true)
|
|
setErrorMessage(null)
|
|
|
|
try {
|
|
const { token } = await authService.login({ username, password })
|
|
const payload = decodeJwtPayload<{ role?: string }>(token)
|
|
const role = resolveRole(payload?.role)
|
|
login(token, role, username)
|
|
} catch (error) {
|
|
const fallback = 'Não foi possível autenticar. Verifique suas credenciais.'
|
|
if (axios.isAxiosError(error)) {
|
|
setErrorMessage(error.response?.data?.error ?? fallback)
|
|
} else if (error instanceof Error) {
|
|
setErrorMessage(error.message)
|
|
} else {
|
|
setErrorMessage(fallback)
|
|
}
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="flex min-h-screen items-center justify-center bg-gray-100">
|
|
<form
|
|
onSubmit={onSubmit}
|
|
className="w-full max-w-md space-y-4 rounded-lg bg-white p-8 shadow-lg"
|
|
>
|
|
<h1 className="text-2xl font-bold text-medicalBlue">Acesso ao Marketplace</h1>
|
|
<p className="text-sm text-gray-600">Informe suas credenciais para acessar o marketplace.</p>
|
|
{errorMessage && (
|
|
<div className="rounded border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700">
|
|
{errorMessage}
|
|
</div>
|
|
)}
|
|
<div className="space-y-2">
|
|
<label className="text-sm font-medium text-gray-700" htmlFor="username">
|
|
Usuário
|
|
</label>
|
|
<input
|
|
id="username"
|
|
name="username"
|
|
autoComplete="username"
|
|
className="w-full rounded border border-gray-200 px-3 py-2"
|
|
value={username}
|
|
onChange={(e) => setUsername(e.target.value)}
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<label className="text-sm font-medium text-gray-700" htmlFor="password">
|
|
Senha
|
|
</label>
|
|
<input
|
|
id="password"
|
|
name="password"
|
|
type="password"
|
|
autoComplete="current-password"
|
|
className="w-full rounded border border-gray-200 px-3 py-2"
|
|
value={password}
|
|
onChange={(e) => setPassword(e.target.value)}
|
|
/>
|
|
</div>
|
|
<button
|
|
type="submit"
|
|
className="w-full rounded bg-healthGreen px-4 py-2 font-semibold text-white disabled:cursor-not-allowed disabled:opacity-70"
|
|
disabled={loading}
|
|
>
|
|
{loading ? 'Entrando...' : 'Entrar'}
|
|
</button>
|
|
</form>
|
|
</div>
|
|
)
|
|
}
|