aboutsummaryrefslogtreecommitdiffstats
path: root/frontend/src/components/Login.tsx
diff options
context:
space:
mode:
authorAdam Mathes <adam@adammathes.com>2026-02-12 21:50:56 -0800
committerAdam Mathes <adam@adammathes.com>2026-02-12 21:50:56 -0800
commit42f1b4de384bcbbdab3b80d8e5cc53b36fcffd50 (patch)
tree3a5aab90607131231ec68367f8cc00425d7dc516 /frontend/src/components/Login.tsx
parent9db2500fb340ef304c0f15f4379bc33589df9a63 (diff)
downloadneko-42f1b4de384bcbbdab3b80d8e5cc53b36fcffd50.tar.gz
neko-42f1b4de384bcbbdab3b80d8e5cc53b36fcffd50.tar.bz2
neko-42f1b4de384bcbbdab3b80d8e5cc53b36fcffd50.zip
Implement frontend login logic with >90% coverage
Diffstat (limited to 'frontend/src/components/Login.tsx')
-rw-r--r--frontend/src/components/Login.tsx54
1 files changed, 54 insertions, 0 deletions
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>
+ );
+}