aboutsummaryrefslogtreecommitdiffhomepage
path: root/frontend/src/pages
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2025-11-02 00:00:35 +0900
committernsfisis <nsfisis@gmail.com>2025-11-02 00:00:35 +0900
commit104341ddc4add57f83c58cb3fabb23b6fbfdd3e4 (patch)
tree862b109fe257e6170a88929729dae3bddfb6eb49 /frontend/src/pages
parentba1e0c904f810193f25d4f88cc2bb168f1d625fe (diff)
downloadfeedaka-feat/multi-user.tar.gz
feedaka-feat/multi-user.tar.zst
feedaka-feat/multi-user.zip
Diffstat (limited to 'frontend/src/pages')
-rw-r--r--frontend/src/pages/Login.tsx133
-rw-r--r--frontend/src/pages/index.ts1
2 files changed, 134 insertions, 0 deletions
diff --git a/frontend/src/pages/Login.tsx b/frontend/src/pages/Login.tsx
new file mode 100644
index 0000000..5703047
--- /dev/null
+++ b/frontend/src/pages/Login.tsx
@@ -0,0 +1,133 @@
+import { useState } from "react";
+import { useLocation } from "wouter";
+import { useAuth } from "../contexts/AuthContext";
+
+export function Login() {
+ const [username, setUsername] = useState("");
+ const [password, setPassword] = useState("");
+ const [error, setError] = useState("");
+ const [isLoading, setIsLoading] = useState(false);
+ const { login } = useAuth();
+ const [, setLocation] = useLocation();
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ setError("");
+ setIsLoading(true);
+
+ try {
+ const success = await login(username, password);
+ if (success) {
+ setLocation("/");
+ } else {
+ setError("Invalid username or password");
+ }
+ } catch (_err) {
+ setError("An error occurred during login");
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ return (
+ <div
+ style={{
+ display: "flex",
+ justifyContent: "center",
+ alignItems: "center",
+ minHeight: "100vh",
+ backgroundColor: "#f5f5f5",
+ }}
+ >
+ <div
+ style={{
+ backgroundColor: "white",
+ padding: "2rem",
+ borderRadius: "8px",
+ boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
+ width: "100%",
+ maxWidth: "400px",
+ }}
+ >
+ <h1 style={{ marginBottom: "1.5rem", textAlign: "center" }}>
+ Feedaka Login
+ </h1>
+ <form onSubmit={handleSubmit}>
+ <div style={{ marginBottom: "1rem" }}>
+ <label
+ htmlFor="username"
+ style={{ display: "block", marginBottom: "0.5rem" }}
+ >
+ Username
+ </label>
+ <input
+ id="username"
+ type="text"
+ value={username}
+ onChange={(e) => setUsername(e.target.value)}
+ required
+ style={{
+ width: "100%",
+ padding: "0.5rem",
+ border: "1px solid #ccc",
+ borderRadius: "4px",
+ }}
+ disabled={isLoading}
+ />
+ </div>
+ <div style={{ marginBottom: "1rem" }}>
+ <label
+ htmlFor="password"
+ style={{ display: "block", marginBottom: "0.5rem" }}
+ >
+ Password
+ </label>
+ <input
+ id="password"
+ type="password"
+ value={password}
+ onChange={(e) => setPassword(e.target.value)}
+ required
+ style={{
+ width: "100%",
+ padding: "0.5rem",
+ border: "1px solid #ccc",
+ borderRadius: "4px",
+ }}
+ disabled={isLoading}
+ />
+ </div>
+ {error && (
+ <div
+ style={{
+ color: "red",
+ marginBottom: "1rem",
+ padding: "0.5rem",
+ backgroundColor: "#fee",
+ borderRadius: "4px",
+ }}
+ >
+ {error}
+ </div>
+ )}
+ <button
+ type="submit"
+ disabled={isLoading}
+ style={{
+ width: "100%",
+ padding: "0.75rem",
+ backgroundColor: "#007bff",
+ color: "white",
+ border: "none",
+ borderRadius: "4px",
+ cursor: isLoading ? "not-allowed" : "pointer",
+ opacity: isLoading ? 0.7 : 1,
+ }}
+ >
+ {isLoading ? "Logging in..." : "Login"}
+ </button>
+ </form>
+ </div>
+ </div>
+ );
+}
diff --git a/frontend/src/pages/index.ts b/frontend/src/pages/index.ts
index a037a9d..dd2df8f 100644
--- a/frontend/src/pages/index.ts
+++ b/frontend/src/pages/index.ts
@@ -1,3 +1,4 @@
+export { Login } from "./Login";
export { NotFound } from "./NotFound";
export { ReadArticles } from "./ReadArticles";
export { Settings } from "./Settings";