|
|
import React, { useState, type FormEvent } from "react"; |
|
|
import { Mail, Lock, LogIn } from "lucide-react"; |
|
|
import API from "../../api/api"; |
|
|
import { useAuth } from "../context/AuthContext"; |
|
|
|
|
|
interface SignInProps { |
|
|
onSwitchToSignUp: () => void; |
|
|
} |
|
|
|
|
|
const SignIn: React.FC<SignInProps> = ({ onSwitchToSignUp }) => { |
|
|
const [email, setEmail] = useState(""); |
|
|
const [password, setPassword] = useState(""); |
|
|
const [error, setError] = useState(""); |
|
|
const { login } = useAuth(); |
|
|
|
|
|
const handleSubmit = async (e: FormEvent) => { |
|
|
e.preventDefault(); |
|
|
setError(""); |
|
|
|
|
|
try { |
|
|
const res = await API.post("/auth/login", { email, password }); |
|
|
|
|
|
|
|
|
login( |
|
|
res.data.username || res.data.user?.username || "User", |
|
|
res.data.access_token |
|
|
); |
|
|
} catch (err: any) { |
|
|
console.error("Login error:", err); |
|
|
|
|
|
let errorMessage = "Login failed."; |
|
|
if (err.response?.data?.detail) { |
|
|
const detail = err.response.data.detail; |
|
|
if (typeof detail === "string") errorMessage = detail; |
|
|
else if (Array.isArray(detail)) { |
|
|
const first = detail[0]; |
|
|
errorMessage = `${first.loc.join(" -> ")}: ${first.msg}`; |
|
|
} |
|
|
} |
|
|
|
|
|
setError(errorMessage); |
|
|
} |
|
|
}; |
|
|
|
|
|
return ( |
|
|
<> |
|
|
<h2 className="text-3xl font-bold mb-8 text-center text-white"> |
|
|
Welcome Back |
|
|
</h2> |
|
|
|
|
|
{error && <p className="text-red-400 text-center mb-3">{error}</p>} |
|
|
|
|
|
<form className="space-y-5" onSubmit={handleSubmit}> |
|
|
<div> |
|
|
<label className="block text-sm mb-1 text-gray-300">Email</label> |
|
|
<div className="relative"> |
|
|
<Mail className="w-5 h-5 absolute left-3 top-1/2 -translate-y-1/2 text-blue-400" /> |
|
|
<input |
|
|
type="text" |
|
|
placeholder="username or email" |
|
|
value={email} |
|
|
onChange={(e) => setEmail(e.target.value)} |
|
|
className="w-full pl-10 py-3 bg-slate-800 border border-slate-700 text-white rounded-lg" |
|
|
required |
|
|
/> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div> |
|
|
<label className="block text-sm mb-1 text-gray-300">Password</label> |
|
|
<div className="relative"> |
|
|
<Lock className="w-5 h-5 absolute left-3 top-1/2 -translate-y-1/2 text-blue-400" /> |
|
|
<input |
|
|
type="password" |
|
|
placeholder="••••••••" |
|
|
value={password} |
|
|
onChange={(e) => setPassword(e.target.value)} |
|
|
className="w-full pl-10 py-3 bg-slate-800 border border-slate-700 text-white rounded-lg" |
|
|
required |
|
|
/> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<button |
|
|
type="submit" |
|
|
className="w-full px-5 py-3 rounded-lg bg-gradient-to-r from-blue-500 to-gray-500 text-white flex items-center justify-center gap-2" |
|
|
> |
|
|
<LogIn className="w-5 h-5" /> |
|
|
Sign In |
|
|
</button> |
|
|
</form> |
|
|
|
|
|
<p className="mt-8 text-center text-sm text-gray-400"> |
|
|
Don’t have an account?{" "} |
|
|
<button onClick={onSwitchToSignUp} className="ml-2 text-blue-400"> |
|
|
Sign Up |
|
|
</button> |
|
|
</p> |
|
|
</> |
|
|
); |
|
|
}; |
|
|
|
|
|
export default SignIn; |
|
|
|