From 0a903bad0b5bbb166066250384b41e8bc48d81ae Mon Sep 17 00:00:00 2001 From: hz Date: Mon, 12 May 2025 22:24:07 -0700 Subject: [PATCH] Adding login auth --- src/App.jsx | 42 ++++++++--- src/AuthContext.jsx | 27 +++++++ src/components/Layout.jsx | 39 ++++++++++ src/index.css | 11 ++- src/main.jsx | 23 +++--- src/pages/Login.jsx | 149 +++++++++++++++++++++++++++----------- src/pages/Register.jsx | 94 +++++++++++++++++++----- 7 files changed, 299 insertions(+), 86 deletions(-) create mode 100644 src/AuthContext.jsx create mode 100644 src/components/Layout.jsx diff --git a/src/App.jsx b/src/App.jsx index b2cefcf..eb3075a 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,17 +1,37 @@ -import React from 'react'; -import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; -import Login from './pages/Login'; -import Register from './pages/Register'; +import React from "react"; +import { BrowserRouter as Router, Routes, Route, useNavigate } from "react-router-dom"; +import Login from "./pages/Login"; +import Register from "./pages/Register"; +import { useAuth } from "./AuthContext"; const App = () => { + const { isAuthenticated, logout } = useAuth(); + return ( - - - } /> - } /> - } /> - - +
+ {/* Logout button */} + {isAuthenticated && ( +
+ +
+ )} + + {/* Centered content */} +
+ + } /> + } /> + } /> + +
+
); }; diff --git a/src/AuthContext.jsx b/src/AuthContext.jsx new file mode 100644 index 0000000..22026c1 --- /dev/null +++ b/src/AuthContext.jsx @@ -0,0 +1,27 @@ +import React, { createContext, useContext, useState } from "react"; + +const AuthContext = createContext(); + +export const AuthProvider = ({ children }) => { + const [isLoggedIn, setIsLoggedIn] = useState( + !!localStorage.getItem("authToken") + ); + + const login = (token) => { + localStorage.setItem("authToken", token); + setIsLoggedIn(true); + }; + + const logout = () => { + localStorage.removeItem("authToken"); + setIsLoggedIn(false); + }; + + return ( + + {children} + + ); +}; + +export const useAuth = () => useContext(AuthContext); diff --git a/src/components/Layout.jsx b/src/components/Layout.jsx new file mode 100644 index 0000000..0eeacdf --- /dev/null +++ b/src/components/Layout.jsx @@ -0,0 +1,39 @@ +import React from "react"; +import { useAuth } from "../AuthContext"; +import { useNavigate } from "react-router-dom"; + +const Layout = ({ children }) => { + const { isLoggedIn, logout } = useAuth(); + const navigate = useNavigate(); + + const handleLogout = () => { + logout(); + navigate("/login"); + }; + + return ( +
+ {isLoggedIn && ( + + )} + {children} +
+ ); +}; + +export default Layout; diff --git a/src/index.css b/src/index.css index 08a3ac9..b36d18b 100644 --- a/src/index.css +++ b/src/index.css @@ -22,12 +22,13 @@ a:hover { color: #535bf2; } -body { +/* index.css or global stylesheet */ +body, html, #root { + height: 100%; margin: 0; display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; + align-items: center; + justify-content: center; } h1 { @@ -66,3 +67,5 @@ button:focus-visible { background-color: #f9f9f9; } } + + diff --git a/src/main.jsx b/src/main.jsx index b9a1a6d..73e10b5 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -1,10 +1,15 @@ -import { StrictMode } from 'react' -import { createRoot } from 'react-dom/client' -import './index.css' -import App from './App.jsx' +import React from "react"; +import ReactDOM from "react-dom/client"; +import App from "./App"; +import { BrowserRouter } from "react-router-dom"; +import { AuthProvider } from "./AuthContext"; -createRoot(document.getElementById('root')).render( - - - , -) +ReactDOM.createRoot(document.getElementById("root")).render( + + + + + + + +); diff --git a/src/pages/Login.jsx b/src/pages/Login.jsx index ab1a8c5..9f328f7 100644 --- a/src/pages/Login.jsx +++ b/src/pages/Login.jsx @@ -1,65 +1,128 @@ import React, { useState } from "react"; import { useNavigate } from "react-router-dom"; import config from "../config"; +import { useAuth } from "../AuthContext"; + +const styles = { + form: { + backgroundColor: "#2a2a2a", + padding: "2rem", + borderRadius: "8px", + boxShadow: "0 0 10px rgba(0,0,0,0.5)", + width: "100%", + maxWidth: "350px", + display: "flex", + flexDirection: "column", + gap: "1rem", + }, + title: { + textAlign: "center", + color: "#f2f2f2", + marginBottom: "1rem", + }, + input: { + padding: "0.75rem", + borderRadius: "4px", + border: "1px solid #444", + backgroundColor: "#333", + color: "#eee", + outline: "none", + }, + buttonRow: { + display: "flex", + justifyContent: "space-between", + gap: "0.5rem", + }, + button: { + flex: 1, + padding: "0.75rem", + borderRadius: "4px", + border: "none", + backgroundColor: "#555", + color: "#fff", + cursor: "pointer", + transition: "background 0.2s ease", + }, +}; const Login = () => { - const [username, setUsername] = useState(""); - const [password, setPassword] = useState(""); const navigate = useNavigate(); + const { login } = useAuth(); - const handleLogin = async (e) => { + const [form, setForm] = useState({ + username: "", + password: "", + }); + + const handleChange = (e) => { + setForm({ ...form, [e.target.name]: e.target.value }); + }; + + const handleSubmit = async (e) => { e.preventDefault(); - const response = await fetch(`${config.API_BASE_URL}/api/Auth/login`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ username, password }), - }); + const payload = { + username: form.username, + password: form.password, + }; - if (response.ok) { - const data = await response.json(); - // Save token etc. - console.log("Login successful:", data); - // Redirect or update state - } else { - alert("Login failed."); + try { + const res = await fetch(`${config.apiBaseUrl}/api/Auth/login`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(payload), + }); + + if (!res.ok) { + const data = await res.json(); + throw new Error(data.message || "Login failed"); + } + + const data = await res.json(); + login(data.token); // Save to context/localStorage + navigate("/"); + } catch (err) { + console.error("Login error:", err); + alert("Login failed: " + err.message); } }; - const goToRegister = () => { - navigate("/register"); - }; - return ( -
-

Login

-
- setUsername(e.target.value)} - required - /> -
- setPassword(e.target.value)} - required - /> -
- + +

Login

+ + +
+ - -
+
+ ); }; diff --git a/src/pages/Register.jsx b/src/pages/Register.jsx index 449f149..7113639 100644 --- a/src/pages/Register.jsx +++ b/src/pages/Register.jsx @@ -2,14 +2,56 @@ import React, { useState } from "react"; import { useNavigate } from "react-router-dom"; import config from "../config"; +const styles = { + form: { + backgroundColor: "#2a2a2a", + padding: "2rem", + borderRadius: "8px", + boxShadow: "0 0 10px rgba(0,0,0,0.5)", + width: "100%", + maxWidth: "350px", + display: "flex", + flexDirection: "column", + gap: "1rem", + }, + title: { + textAlign: "center", + color: "#f2f2f2", + marginBottom: "1rem", + }, + input: { + padding: "0.75rem", + borderRadius: "4px", + border: "1px solid #444", + backgroundColor: "#333", + color: "#eee", + outline: "none", + }, + buttonRow: { + display: "flex", + justifyContent: "space-between", + gap: "0.5rem", + }, + button: { + flex: 1, + padding: "0.75rem", + borderRadius: "4px", + border: "none", + backgroundColor: "#555", + color: "#fff", + cursor: "pointer", + transition: "background 0.2s ease", + }, +}; + const Register = () => { - const navigate = useNavigate(); const [form, setForm] = useState({ username: "", email: "", password: "", }); - const [error, setError] = useState(""); + + const navigate = useNavigate(); const handleChange = (e) => { setForm({ ...form, [e.target.name]: e.target.value }); @@ -18,12 +60,6 @@ const Register = () => { const handleSubmit = async (e) => { e.preventDefault(); - const payload = { - username: form.username, - password: form.password, - email: form.email, - }; - try { const res = await fetch(`${config.apiBaseUrl}/api/Auth/register`, { method: "POST", @@ -42,7 +78,7 @@ const Register = () => { throw new Error(data.message || "Registration failed"); } - alert("Success!"); + alert("Registration successful!"); navigate("/login"); } catch (err) { console.error("Register error:", err); @@ -51,32 +87,52 @@ const Register = () => { }; return ( -
-

Register

- {error &&

{error}

} -
+
+ +

Register

- +
+ + +
);