| [700e2f9] | 1 | import { type Component, createSignal } from "solid-js";
|
|---|
| 2 | import { useNavigate } from "@solidjs/router";
|
|---|
| 3 | import { useAuth } from "@/context/AuthContext";
|
|---|
| 4 | import { authApi } from "@/api/auth";
|
|---|
| 5 |
|
|---|
| 6 | interface LoginFormProps {
|
|---|
| 7 | onSwitchToRegister: () => void;
|
|---|
| 8 | }
|
|---|
| 9 |
|
|---|
| 10 | const LoginForm: Component<LoginFormProps> = (props) => {
|
|---|
| 11 | const [error, setError] = createSignal("");
|
|---|
| 12 | const [isLoading, setIsLoading] = createSignal(false);
|
|---|
| 13 | const navigate = useNavigate();
|
|---|
| 14 | const { login } = useAuth();
|
|---|
| 15 |
|
|---|
| 16 | const [loginUsername, setLoginUsername] = createSignal("");
|
|---|
| 17 | const [loginPassword, setLoginPassword] = createSignal("");
|
|---|
| 18 |
|
|---|
| 19 | const handleLogin = async (e: Event) => {
|
|---|
| 20 | e.preventDefault();
|
|---|
| 21 | setError("");
|
|---|
| 22 | setIsLoading(true);
|
|---|
| 23 |
|
|---|
| 24 | try {
|
|---|
| 25 | const response = await authApi.login({
|
|---|
| 26 | username: loginUsername().trim(),
|
|---|
| 27 | password: loginPassword(),
|
|---|
| 28 | });
|
|---|
| 29 |
|
|---|
| 30 | login(response);
|
|---|
| 31 | navigate("/");
|
|---|
| 32 | } catch (err) {
|
|---|
| 33 | setError(
|
|---|
| 34 | err instanceof Error
|
|---|
| 35 | ? err.message
|
|---|
| 36 | : "Error has occurred while logging in. Please try again.",
|
|---|
| 37 | );
|
|---|
| 38 | } finally {
|
|---|
| 39 | setIsLoading(false);
|
|---|
| 40 | }
|
|---|
| 41 | };
|
|---|
| 42 |
|
|---|
| 43 | return (
|
|---|
| 44 | <form class="mt-8 space-y-6" onSubmit={handleLogin}>
|
|---|
| 45 | {error() && (
|
|---|
| 46 | <div class="rounded-md bg-red-50 p-4">
|
|---|
| 47 | <div class="text-sm text-red-700">{error()}</div>
|
|---|
| 48 | </div>
|
|---|
| 49 | )}
|
|---|
| 50 |
|
|---|
| 51 | <div class="rounded-md space-y-4">
|
|---|
| 52 | <div>
|
|---|
| 53 | <label
|
|---|
| 54 | for="username"
|
|---|
| 55 | class="block text-sm font-medium text-gray-700 mb-1"
|
|---|
| 56 | >
|
|---|
| 57 | Username
|
|---|
| 58 | </label>
|
|---|
| 59 | <input
|
|---|
| 60 | id="username"
|
|---|
| 61 | name="username"
|
|---|
| 62 | type="text"
|
|---|
| 63 | required
|
|---|
| 64 | class="appearance-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-md focus:outline-none focus:ring-blue-500 focus:border-blue-500 focus:z-10 sm:text-sm"
|
|---|
| 65 | placeholder="Enter your username"
|
|---|
| 66 | value={loginUsername()}
|
|---|
| 67 | onInput={(e) => setLoginUsername(e.currentTarget.value)}
|
|---|
| 68 | />
|
|---|
| 69 | </div>
|
|---|
| 70 |
|
|---|
| 71 | <div>
|
|---|
| 72 | <label
|
|---|
| 73 | for="password"
|
|---|
| 74 | class="block text-sm font-medium text-gray-700 mb-1"
|
|---|
| 75 | >
|
|---|
| 76 | Password
|
|---|
| 77 | </label>
|
|---|
| 78 | <input
|
|---|
| 79 | id="password"
|
|---|
| 80 | name="password"
|
|---|
| 81 | type="password"
|
|---|
| 82 | required
|
|---|
| 83 | class="appearance-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-md focus:outline-none focus:ring-blue-500 focus:border-blue-500 focus:z-10 sm:text-sm"
|
|---|
| 84 | placeholder="Enter your password"
|
|---|
| 85 | value={loginPassword()}
|
|---|
| 86 | onInput={(e) => setLoginPassword(e.currentTarget.value)}
|
|---|
| 87 | />
|
|---|
| 88 | </div>
|
|---|
| 89 | </div>
|
|---|
| 90 |
|
|---|
| 91 | <div>
|
|---|
| 92 | <button
|
|---|
| 93 | type="submit"
|
|---|
| 94 | disabled={isLoading()}
|
|---|
| 95 | class="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
|---|
| 96 | >
|
|---|
| 97 | {isLoading() ? "Signing in..." : "Sign in"}
|
|---|
| 98 | </button>
|
|---|
| 99 | </div>
|
|---|
| 100 |
|
|---|
| 101 | <div class="text-center text-sm">
|
|---|
| 102 | <span class="text-gray-600">Don't have an account? </span>
|
|---|
| 103 | <button
|
|---|
| 104 | type="button"
|
|---|
| 105 | onClick={props.onSwitchToRegister}
|
|---|
| 106 | class="font-medium text-blue-600 hover:text-blue-500"
|
|---|
| 107 | >
|
|---|
| 108 | Sign up
|
|---|
| 109 | </button>
|
|---|
| 110 | </div>
|
|---|
| 111 | </form>
|
|---|
| 112 | );
|
|---|
| 113 | };
|
|---|
| 114 |
|
|---|
| 115 | export default LoginForm;
|
|---|