From 5f476542e28e5b961a6a4db405c266e7d65c7e33 Mon Sep 17 00:00:00 2001 From: Matteo Date: Sat, 24 Jan 2026 17:12:23 +0100 Subject: [PATCH] feat(frontend): add login and register pages - Add Login page with email/password form - Add Register page with email validation - Add forgot password link to login page - Update App.tsx with auth routes and AuthProvider - Add email validation in registration form --- frontend/src/App.tsx | 72 +++++++++++++++--- frontend/src/pages/Login.tsx | 111 ++++++++++++++++++++++++++++ frontend/src/pages/Register.tsx | 126 ++++++++++++++++++++++++++++++++ 3 files changed, 298 insertions(+), 11 deletions(-) create mode 100644 frontend/src/pages/Login.tsx create mode 100644 frontend/src/pages/Register.tsx diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index efc99e9..dcfec97 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,23 +1,73 @@ -import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; +import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom'; import { Dashboard } from './pages/Dashboard'; import { Editor } from './pages/Editor'; import { Settings } from './pages/Settings'; +import { Profile } from './pages/Profile'; +import { Login } from './pages/Login'; +import { Register } from './pages/Register'; +import { PasswordResetRequest } from './pages/PasswordResetRequest'; +import { PasswordResetConfirm } from './pages/PasswordResetConfirm'; import { ThemeProvider } from './context/ThemeContext'; import { UploadProvider } from './context/UploadContext'; +import { AuthProvider } from './context/AuthContext'; +import { ProtectedRoute } from './components/ProtectedRoute'; function App() { return ( - - - - } /> - } /> - } /> - } /> - - - + + + + + } /> + } /> + } /> + } /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + } /> + + + + ); } diff --git a/frontend/src/pages/Login.tsx b/frontend/src/pages/Login.tsx new file mode 100644 index 0000000..e0ba504 --- /dev/null +++ b/frontend/src/pages/Login.tsx @@ -0,0 +1,111 @@ +import React, { useState } from 'react'; +import { useNavigate, Link } from 'react-router-dom'; +import { useAuth } from '../context/AuthContext'; +import { Logo } from '../components/Logo'; + +export const Login: React.FC = () => { + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [error, setError] = useState(''); + const [loading, setLoading] = useState(false); + const { login } = useAuth(); + const navigate = useNavigate(); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setError(''); + setLoading(true); + + try { + await login(email, password); + navigate('/'); + } catch (err: unknown) { + const message = err instanceof Error ? err.message : 'Failed to login'; + setError(message); + } finally { + setLoading(false); + } + }; + + return ( +
+
+
+ +

+ Sign in to your account +

+

+ Or{' '} + + create a new account + +

+
+
+ {error && ( +
+
{error}
+
+ )} +
+
+ + setEmail(e.target.value)} + /> +
+
+ + setPassword(e.target.value)} + /> +
+
+ +
+ + Forgot your password? + +
+ +
+ +
+
+
+
+ ); +}; \ No newline at end of file diff --git a/frontend/src/pages/Register.tsx b/frontend/src/pages/Register.tsx new file mode 100644 index 0000000..7ab61ef --- /dev/null +++ b/frontend/src/pages/Register.tsx @@ -0,0 +1,126 @@ +import React, { useState } from 'react'; +import { useNavigate, Link } from 'react-router-dom'; +import { useAuth } from '../context/AuthContext'; +import { Logo } from '../components/Logo'; + +export const Register: React.FC = () => { + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [name, setName] = useState(''); + const [error, setError] = useState(''); + const [loading, setLoading] = useState(false); + const { register } = useAuth(); + const navigate = useNavigate(); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setError(''); + + if (password.length < 8) { + setError('Password must be at least 8 characters long'); + return; + } + + setLoading(true); + + try { + await register(email, password, name); + navigate('/'); + } catch (err: unknown) { + const message = err instanceof Error ? err.message : 'Failed to register'; + setError(message); + } finally { + setLoading(false); + } + }; + + return ( +
+
+
+ +

+ Create your account +

+

+ Or{' '} + + sign in to your existing account + +

+
+
+ {error && ( +
+
{error}
+
+ )} +
+
+ + setName(e.target.value)} + /> +
+
+ + setEmail(e.target.value)} + /> +
+
+ + setPassword(e.target.value)} + /> +
+
+ +
+ +
+
+
+
+ ); +}; \ No newline at end of file