| 1 | import { useState } from "react";
|
|---|
| 2 | import { Link, useNavigate } from "react-router-dom";
|
|---|
| 3 | import { toast } from "react-toastify";
|
|---|
| 4 | import axiosInstance, { scheduleTokenRefresh } from "../api/axiosInstance";
|
|---|
| 5 | import { useAuth } from "../context/authContext";
|
|---|
| 6 | import type { User } from "../utils/types";
|
|---|
| 7 |
|
|---|
| 8 | const Login = () => {
|
|---|
| 9 | const [username, setUsername] = useState("");
|
|---|
| 10 | const [password, setPassword] = useState("");
|
|---|
| 11 | const [error, setError] = useState<string | null>(null);
|
|---|
| 12 | const { setUser } = useAuth();
|
|---|
| 13 | const navigate = useNavigate();
|
|---|
| 14 |
|
|---|
| 15 | const handleLogin = async (e: React.FormEvent) => {
|
|---|
| 16 | e.preventDefault();
|
|---|
| 17 | try {
|
|---|
| 18 | const response = await axiosInstance.post<{
|
|---|
| 19 | user: User;
|
|---|
| 20 | tokenExpiresIn: number;
|
|---|
| 21 | }>("/auth/login", { username, password });
|
|---|
| 22 | scheduleTokenRefresh(response.data.tokenExpiresIn);
|
|---|
| 23 | setUser(response.data.user);
|
|---|
| 24 | navigate("/");
|
|---|
| 25 | toast.success("Login successful!");
|
|---|
| 26 | } catch (error: any) {
|
|---|
| 27 | const errorMessage =
|
|---|
| 28 | error.response?.data?.error ||
|
|---|
| 29 | "Login failed. Please check your credentials.";
|
|---|
| 30 | setError(`Login failed: ${errorMessage}`);
|
|---|
| 31 | }
|
|---|
| 32 | };
|
|---|
| 33 | return (
|
|---|
| 34 | <div className="min-h-screen bg-linear-to-br from-[#1e1e2e] to-[#0f0f1e] flex items-center justify-center px-4">
|
|---|
| 35 | <div className="w-full max-w-md">
|
|---|
| 36 | <div className="text-center mb-8">
|
|---|
| 37 | <h1 className="text-4xl font-extrabold text-white mb-2">
|
|---|
| 38 | Welcome Back
|
|---|
| 39 | </h1>
|
|---|
| 40 | <p className="text-gray-400">Log in to continue to FinkWave</p>
|
|---|
| 41 | </div>
|
|---|
| 42 |
|
|---|
| 43 | <form
|
|---|
| 44 | onSubmit={handleLogin}
|
|---|
| 45 | className="bg-[#181818] rounded-xl p-8 space-y-6"
|
|---|
| 46 | >
|
|---|
| 47 | {error && (
|
|---|
| 48 | <div className="bg-red-500/10 border border-red-500/20 rounded-lg p-3">
|
|---|
| 49 | <p className="text-red-400 text-sm">{error}</p>
|
|---|
| 50 | </div>
|
|---|
| 51 | )}
|
|---|
| 52 |
|
|---|
| 53 | <div>
|
|---|
| 54 | <label
|
|---|
| 55 | className="block text-sm font-medium text-gray-300 mb-2"
|
|---|
| 56 | htmlFor="username"
|
|---|
| 57 | >
|
|---|
| 58 | Username
|
|---|
| 59 | </label>
|
|---|
| 60 | <input
|
|---|
| 61 | type="text"
|
|---|
| 62 | id="username"
|
|---|
| 63 | className="w-full bg-[#282828] border border-white/10 rounded-lg py-3 px-4 text-white placeholder-gray-500 focus:outline-none focus:border-[#1db954] focus:ring-1 focus:ring-[#1db954] transition-all"
|
|---|
| 64 | placeholder="Enter your username"
|
|---|
| 65 | value={username}
|
|---|
| 66 | onChange={(e) => setUsername(e.target.value)}
|
|---|
| 67 | />
|
|---|
| 68 | </div>
|
|---|
| 69 |
|
|---|
| 70 | <div>
|
|---|
| 71 | <label
|
|---|
| 72 | className="block text-sm font-medium text-gray-300 mb-2"
|
|---|
| 73 | htmlFor="password"
|
|---|
| 74 | >
|
|---|
| 75 | Password
|
|---|
| 76 | </label>
|
|---|
| 77 | <input
|
|---|
| 78 | type="password"
|
|---|
| 79 | id="password"
|
|---|
| 80 | className="w-full bg-[#282828] border border-white/10 rounded-lg py-3 px-4 text-white placeholder-gray-500 focus:outline-none focus:border-[#1db954] focus:ring-1 focus:ring-[#1db954] transition-all"
|
|---|
| 81 | placeholder="Enter your password"
|
|---|
| 82 | value={password}
|
|---|
| 83 | onChange={(e) => setPassword(e.target.value)}
|
|---|
| 84 | />
|
|---|
| 85 | </div>
|
|---|
| 86 |
|
|---|
| 87 | <button
|
|---|
| 88 | type="submit"
|
|---|
| 89 | className="w-full py-3 bg-[#1db954] rounded-full text-black font-semibold hover:bg-[#1ed760] transition-colors cursor-pointer"
|
|---|
| 90 | >
|
|---|
| 91 | Log In
|
|---|
| 92 | </button>
|
|---|
| 93 |
|
|---|
| 94 | <p className="text-center text-sm text-gray-400">
|
|---|
| 95 | Don't have an account?{" "}
|
|---|
| 96 | <Link
|
|---|
| 97 | to="/register"
|
|---|
| 98 | className="text-[#1db954] hover:underline font-medium"
|
|---|
| 99 | >
|
|---|
| 100 | Sign up
|
|---|
| 101 | </Link>
|
|---|
| 102 | </p>
|
|---|
| 103 | </form>
|
|---|
| 104 | </div>
|
|---|
| 105 | </div>
|
|---|
| 106 | );
|
|---|
| 107 | };
|
|---|
| 108 |
|
|---|
| 109 | export default Login;
|
|---|