diff --git a/src/App.jsx b/src/App.jsx index ae19eba..e7c55ab 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,17 +1,14 @@ -import { - BrowserRouter, - Route, - Routes, -} from 'react-router-dom'; -import './App.css'; -import Navbar from './components/NavBar/Navbar'; -import FindABook from './Pages/FindABook'; -import Home from './Pages/home'; -import booksData from '/src/data/booksData.js'; -const URL = 'http://localhost:8000/api/v1/'; +import { BrowserRouter, Route, Routes } from "react-router-dom"; +import "./App.css"; +import Navbar from "./components/NavBar/Navbar"; +import FindABook from "./Pages/FindABook"; +import Home from "./Pages/home"; +import booksData from "/src/data/booksData.js"; +import Signup from "./components/userSignup/Signup"; +const URL = "http://localhost:8000/api/v1/"; function App() { - if (typeof global === 'undefined') { + if (typeof global === "undefined") { window.global = window; } return ( @@ -19,14 +16,9 @@ function App() { - } - /> - } - /> + } /> + } /> + } /> diff --git a/src/components/BookCard/BookCard.jsx b/src/components/BookCard/BookCard.jsx index 3211580..f5c702f 100644 --- a/src/components/BookCard/BookCard.jsx +++ b/src/components/BookCard/BookCard.jsx @@ -1,5 +1,5 @@ -import React from 'react'; -import './BookCard.css'; +import React from "react"; +import "./BookCard.css"; export default function BookCard({ imageLinks = {}, @@ -9,14 +9,11 @@ export default function BookCard({ }) { return (
- Book cover + Book cover

{title}

- By {authors.join(', ')} ({publishedDate}) + By {authors.join(", ")} ({publishedDate})

diff --git a/src/components/userSignup/Signup.css b/src/components/userSignup/Signup.css new file mode 100644 index 0000000..040dcf4 --- /dev/null +++ b/src/components/userSignup/Signup.css @@ -0,0 +1,78 @@ +.signup-wrapper { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; +} + +.signup-container { + width: 300px; + padding: 20px; + border: 1px solid #ccc; + border-radius: 5px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); +} + +.error { + color: red; + font-size: 14px; +} + +input { + width: 100%; + padding: 8px; + margin: 10px 0; + border: 1px solid #ccc; + border-radius: 4px; +} + +button { + width: 100%; + background-color: #007bff; + color: white; + padding: 10px; + border: none; + border-radius: 4px; + cursor: pointer; +} + +button:hover { + background-color: #0056b3; +} + +.password-container { + margin-bottom: 10px; +} + +.password-input-wrapper { + position: relative; + width: 100%; +} + +.password-input-wrapper input { + width: 100%; + padding-right: 30px; +} + +.password-toggle { + position: absolute; + top: 50%; + right: 8px; + transform: translateY(-50%); + border: none; + background: none; + cursor: pointer; + font-size: 14px; + color: #666; + padding: 2px; + height: 24px; + width: 24px; + line-height: 0; + display: flex; + align-items: center; + justify-content: center; +} + +.password-toggle:hover { + color: #333; +} diff --git a/src/components/userSignup/Signup.jsx b/src/components/userSignup/Signup.jsx new file mode 100644 index 0000000..057d15e --- /dev/null +++ b/src/components/userSignup/Signup.jsx @@ -0,0 +1,126 @@ +import React, { useState } from "react"; +import { useNavigate } from "react-router-dom"; +import "./Signup.css"; + +const Signup = () => { + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [name, setName] = useState(""); + const [error, setError] = useState(""); + const [emailError, setEmailError] = useState(""); + const [showPassword, setShowPassword] = useState(false); + const [loading, setLoading] = useState(false); + const navigate = useNavigate(); + + const validateEmail = (email) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); + + const validatePassword = (password) => { + const passwordRegex = + /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{6,}$/; + return passwordRegex.test(password); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + setError(""); + setEmailError(""); + + if (!name || !email || !password) { + setError("All fields are required."); + return; + } + if (!validateEmail(email)) { + setEmailError("Invalid email format."); + return; + } + if (!validatePassword(password)) { + setError( + "Password must include at least one letter, one number, and one special character, and be at least 6 characters long.", + ); + return; + } + + setLoading(true); + + try { + const response = await fetch( + "http://localhost:8000/api/v1/auth/register", + { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ name, email, password }), + }, + ); + + if (response.ok) { + const data = await response.json(); + localStorage.setItem("token", data.token); + navigate("/home"); + } else { + const errorData = await response.json(); + setError(errorData.message || "An unexpected error occurred."); + } + } catch (err) { + setError("Something went wrong. Please try again."); + } finally { + setLoading(false); + } + }; + + return ( +
+
+
+

Signup

+ {error &&

{error}

} + +
+ + setName(e.target.value)} + required + /> +
+ +
+ + setEmail(e.target.value)} + required + /> + {emailError &&

{emailError}

} +
+ +
+ +
+ setPassword(e.target.value)} + required + /> + +
+
+ + +
+
+
+ ); +}; + +export default Signup;