From 42f1b4de384bcbbdab3b80d8e5cc53b36fcffd50 Mon Sep 17 00:00:00 2001
From: Adam Mathes <adam@adammathes.com>
Date: Thu, 12 Feb 2026 21:50:56 -0800
Subject: Implement frontend login logic with >90% coverage

---
 frontend/src/components/Login.tsx | 54 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)
 create mode 100644 frontend/src/components/Login.tsx

(limited to 'frontend/src/components/Login.tsx')

diff --git a/frontend/src/components/Login.tsx b/frontend/src/components/Login.tsx
new file mode 100644
index 0000000..2e8bbf7
--- /dev/null
+++ b/frontend/src/components/Login.tsx
@@ -0,0 +1,54 @@
+import { useState, type FormEvent } from 'react';
+import { useNavigate } from 'react-router-dom';
+import './Login.css';
+
+export default function Login() {
+    const [password, setPassword] = useState('');
+    const [error, setError] = useState('');
+    const navigate = useNavigate();
+
+    const handleSubmit = async (e: FormEvent) => {
+        e.preventDefault();
+        setError('');
+
+        try {
+            // Use URLSearchParams to send as form-urlencoded, matching backend expectation
+            const params = new URLSearchParams();
+            params.append('password', password);
+
+            const res = await fetch('/api/login', {
+                method: 'POST',
+                body: params,
+            });
+
+            if (res.ok) {
+                navigate('/');
+            } else {
+                const data = await res.json();
+                setError(data.message || 'Login failed');
+            }
+        } catch (err) {
+            setError('Network error');
+        }
+    };
+
+    return (
+        <div className="login-container">
+            <form onSubmit={handleSubmit} className="login-form">
+                <h1>neko rss mode</h1>
+                <div className="form-group">
+                    <label htmlFor="password">password</label>
+                    <input
+                        id="password"
+                        type="password"
+                        value={password}
+                        onChange={(e) => setPassword(e.target.value)}
+                        autoFocus
+                    />
+                </div>
+                {error && <div className="error-message">{error}</div>}
+                <button type="submit">login</button>
+            </form>
+        </div>
+    );
+}
-- 
cgit v1.2.3

