| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- import React, { useState } from "react";
- import { useAuth } from "../contexts/AuthContext";
- import { useNavigate, useLocation } from "react-router-dom";
- function LoginForm() {
- const [formData, setFormData] = useState({
- username: "",
- password: "",
- });
- const [error, setError] = useState("");
- const [loading, setLoading] = useState(false);
- const { login } = useAuth();
- const navigate = useNavigate();
- const location = useLocation();
- // Redirect to intended location after login, or to admin dashboard
- const redirectTo = location.state?.from?.pathname || "/admin";
- const handleChange = (e) => {
- const { name, value } = e.target;
- setFormData((prev) => ({ ...prev, [name]: value }));
- };
- const handleSubmit = async (e) => {
- e.preventDefault();
- setLoading(true);
- setError("");
- if (!formData.username.trim() || !formData.password) {
- setError("Please enter both username and password");
- setLoading(false);
- return;
- }
- try {
- const result = await login(
- formData.username.trim(),
- formData.password,
- );
- if (result.success) {
- navigate(redirectTo, { replace: true });
- } else {
- setError(result.error || "Login failed");
- }
- } catch (err) {
- setError("An unexpected error occurred");
- } finally {
- setLoading(false);
- }
- };
- return (
- <div className="min-h-screen theme-bg flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
- <div className="max-w-md w-full space-y-8">
- <div>
- <h2 className="mt-6 text-center text-3xl font-extrabold theme-text">
- Sign in to Admin Panel
- </h2>
- <p className="mt-2 text-center text-sm theme-text-secondary">
- Access the{" "}
- <span className="theme-primary font-semibold">
- Goon
- </span>
- Blog admin interface
- </p>
- </div>
- <form className="mt-8 space-y-6" onSubmit={handleSubmit}>
- <div className="rounded-md shadow-sm -space-y-px">
- <div>
- <label htmlFor="username" className="sr-only">
- Username
- </label>
- <input
- id="username"
- name="username"
- type="text"
- autoComplete="username"
- required
- value={formData.username}
- onChange={handleChange}
- className="relative block w-full px-3 py-2 border theme-border placeholder-gray-500 theme-text rounded-t-md focus:outline-none focus:ring-blue-500 focus:border-blue-500 focus:z-10 sm:text-sm"
- placeholder="Username"
- disabled={loading}
- />
- </div>
- <div>
- <label htmlFor="password" className="sr-only">
- Password
- </label>
- <input
- id="password"
- name="password"
- type="password"
- autoComplete="current-password"
- required
- value={formData.password}
- onChange={handleChange}
- className="relative block w-full px-3 py-2 border theme-border placeholder-gray-500 theme-text rounded-b-md focus:outline-none focus:ring-blue-500 focus:border-blue-500 focus:z-10 sm:text-sm"
- placeholder="Password"
- disabled={loading}
- />
- </div>
- </div>
- {error && (
- <div className="rounded-md bg-red-50 p-4">
- <div className="flex">
- <div className="flex-shrink-0">
- <svg
- className="h-5 w-5 text-red-400"
- viewBox="0 0 20 20"
- fill="currentColor"
- >
- <path
- fillRule="evenodd"
- d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z"
- clipRule="evenodd"
- />
- </svg>
- </div>
- <div className="ml-3">
- <h3 className="text-sm font-medium text-red-800">
- Error
- </h3>
- <div className="mt-1 text-sm text-red-700">
- {error}
- </div>
- </div>
- </div>
- </div>
- )}
- <div>
- <button
- type="submit"
- disabled={loading}
- className="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white btn-theme-primary disabled:opacity-50 disabled:cursor-not-allowed"
- >
- {loading ? (
- <div className="flex items-center">
- <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>
- Signing in...
- </div>
- ) : (
- "Sign in"
- )}
- </button>
- </div>
- <div className="text-center">
- <button
- type="button"
- onClick={() => navigate("/")}
- className="text-sm theme-text-secondary hover:theme-text"
- >
- ← Back to Blog
- </button>
- </div>
- </form>
- </div>
- </div>
- );
- }
- export default LoginForm;
|