Skip to content

Commit b129809

Browse files
committed
Add Register Page
1 parent ff18308 commit b129809

12 files changed

Lines changed: 259 additions & 30 deletions

File tree

Frontend/package-lock.json

Lines changed: 60 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Frontend/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
},
1212
"dependencies": {
1313
"react": "^19.2.0",
14-
"react-dom": "^19.2.0"
14+
"react-dom": "^19.2.0",
15+
"react-router-dom": "^7.9.6"
1516
},
1617
"devDependencies": {
1718
"@eslint/js": "^9.39.1",

Frontend/src/App.tsx

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,22 @@
11
import { useState } from 'react'
2-
import reactLogo from './assets/react.svg'
3-
import viteLogo from '/vite.svg'
42
import './App.css'
3+
import { Route, Routes } from 'react-router-dom'
4+
import { Home } from './Pages/Home'
5+
import { Login } from './Pages/Login'
6+
import { Register } from './Pages/Register'
7+
import { Navbar } from './Components/Navbar'
58

6-
function App() {
7-
const [count, setCount] = useState(0)
8-
9-
return (
9+
function App () {
10+
return(
1011
<>
11-
<div>
12-
<a href="https://vite.dev" target="_blank">
13-
<img src={viteLogo} className="logo" alt="Vite logo" />
14-
</a>
15-
<a href="https://react.dev" target="_blank">
16-
<img src={reactLogo} className="logo react" alt="React logo" />
17-
</a>
18-
</div>
19-
<h1>Vite + React</h1>
20-
<div className="card">
21-
<button onClick={() => setCount((count) => count + 1)}>
22-
count is {count}
23-
</button>
24-
<p>
25-
Edit <code>src/App.tsx</code> and save to test HMR
26-
</p>
27-
</div>
28-
<p className="read-the-docs">
29-
Click on the Vite and React logos to learn more
30-
</p>
12+
<Navbar/>
13+
<Routes>
14+
<Route path='/' element={<Home/>}/>
15+
<Route path='/login' element={<Login/>}/>
16+
<Route path='/Register' element={<Register/>}/>
17+
</Routes>
3118
</>
3219
)
3320
}
3421

35-
export default App
22+
export default App

Frontend/src/Components/Navbar.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Link } from "react-router-dom"
2+
3+
export function Navbar () {
4+
return (
5+
<nav>
6+
<Link to="/">Home</Link> |
7+
<Link to="/login">Login</Link> |
8+
<Link to="/Register">Register</Link>
9+
</nav>
10+
)
11+
}

Frontend/src/Pages/Home.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
export function Home () {
3+
return(
4+
<h1>HOME</h1>
5+
)
6+
}

Frontend/src/Pages/Login.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
export function Login () {
3+
return(
4+
<>
5+
<h2>Login Page</h2>
6+
<input type="text" placeholder="Username"/>
7+
<input type="text" placeholder="Password"/>
8+
<button>Login</button>
9+
</>
10+
)
11+
}

Frontend/src/Pages/Register.tsx

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import { useEffect, useState } from "react"
2+
import { registerUser } from "../api/loginapi"
3+
4+
export function Register () {
5+
const [username, setUsername] = useState("")
6+
const [password, setPassword] = useState("")
7+
const [confirm, setConfirm] = useState("")
8+
const [errors, setErrors] = useState({
9+
username: "",
10+
password: "",
11+
confirm: ""
12+
});
13+
const [serverError, setServerError] = useState("");
14+
const [isSubmitting, setisSubmitting] = useState(false);
15+
16+
const validateUsername = (value: string) => {
17+
if (!value) return "Username is required";
18+
if (value !== value.toLowerCase()) return "Username should be all lowercase"
19+
return "";
20+
}
21+
const validatePassword = (value: string) => {
22+
if (!value) return "Password is required"
23+
if (value.length < 6) return "Password Must Contain atleast 6 Characters"
24+
if (!/\d/.test(value)) return "Password Must contain atleast One number"
25+
if (!/[!@#$%^&*(),.?":{}|<>]/.test(value)) return "Password Must atleast contain a special Character"
26+
return ""
27+
}
28+
const validateConfirm = (pwd, conf) => {
29+
if (!conf) return "Please retype password";
30+
if (pwd !== conf) return "Password do not match"
31+
return "";
32+
};
33+
34+
const onUsernameChange = (e) => {
35+
const v = e.target.value;
36+
setUsername(v)
37+
setErrors((prev) => ({...prev, username:validateUsername(v)}));
38+
setServerError("");
39+
}
40+
const onPasswordChange = (e) => {
41+
const v = e.target.value;
42+
setPassword(v)
43+
setErrors((prev) => ({...prev, password: validatePassword(v), confirm: validateConfirm(v, confirm)}))
44+
setServerError("");
45+
}
46+
const onConfirmChange = (e) => {
47+
const v = e.target.value
48+
setConfirm(v);
49+
setErrors((prev) => ({...prev, confirm: validateConfirm(password, v)}))
50+
setServerError("");
51+
}
52+
53+
const isFormValid =
54+
!errors.username &&
55+
!errors.password &&
56+
!errors.confirm &&
57+
username &&
58+
password &&
59+
confirm;
60+
61+
const handleRegister = async () => {
62+
const uerror = validateUsername(username)
63+
const perror = validatePassword(password)
64+
const cerror = validateConfirm(password, confirm)
65+
setErrors({username: uerror, password: perror, confirm: cerror})
66+
setServerError("");
67+
if (uerror || perror || cerror) return;
68+
69+
setisSubmitting(true);
70+
try{
71+
await registerUser({username, password});
72+
alert("New User Added")
73+
setUsername("");
74+
setPassword("");
75+
setConfirm("");
76+
setErrors({username: "", password: "", confirm: ""});
77+
78+
} catch (err) {
79+
console.log(err)
80+
} finally {setisSubmitting(false);}
81+
}
82+
return(
83+
<>
84+
<h2>Register Page</h2>
85+
<label>
86+
<h4>Username</h4>
87+
<input
88+
type="text"
89+
placeholder="Username"
90+
value={username}
91+
onChange={onUsernameChange}/>
92+
</label>
93+
{errors.username && <div style={{ color: "red" }}>{errors.username}</div>}
94+
95+
<label>
96+
<h4>Password</h4>
97+
<input
98+
type="password"
99+
placeholder="Password"
100+
value={password}
101+
onChange={onPasswordChange}/>
102+
</label>
103+
{errors.password && <div style={{ color: "red" }}>{errors.password}</div>}
104+
105+
<label>
106+
<h4>Retype Password</h4>
107+
<input type="password"
108+
placeholder="Retype Password"
109+
value={confirm}
110+
onChange={onConfirmChange}/>
111+
</label>
112+
113+
{errors.confirm && <div style={{ color: "red" }}>{errors.confirm}</div>}
114+
{serverError && <div style={{ color: "red", marginTop: 8 }}>{serverError}</div>}
115+
<br></br>
116+
<button
117+
onClick={handleRegister}
118+
disabled={!isFormValid || isSubmitting}
119+
style={{ marginTop: 12 }}>
120+
{isSubmitting ? "Registering..." : "Register"}</button>
121+
122+
</>
123+
)
124+
}

Frontend/src/api/loginapi.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
const BASE_URL = 'http://127.0.0.1:8000/'
2+
3+
export const registerUser = async<DT> (user: DT) => {
4+
try{
5+
const response = await fetch(`${BASE_URL}accounts/register/`, {
6+
method :"POST",
7+
headers : {
8+
'Content-Type': "application/json",
9+
},
10+
body : JSON.stringify(user)
11+
});
12+
const data = await response.json()
13+
return data
14+
}catch (err) {
15+
console.log("Post Error", err)
16+
}
17+
18+
}

Frontend/src/main.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ import { StrictMode } from 'react'
22
import { createRoot } from 'react-dom/client'
33
import './index.css'
44
import App from './App.tsx'
5+
import { BrowserRouter } from 'react-router-dom'
56

67
createRoot(document.getElementById('root')!).render(
78
<StrictMode>
9+
<BrowserRouter>
810
<App />
11+
</BrowserRouter>
912
</StrictMode>,
1013
)
0 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)