initial commit

This commit is contained in:
Harikrishnan Gopal
2024-12-03 15:53:50 +05:30
commit 956cf14c53
26 changed files with 22820 additions and 0 deletions

View File

@@ -0,0 +1,101 @@
import React, { useState } from "react";
import { Container, Col, Row } from "react-bootstrap";
import axios from "axios";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
function ForgetPwPage() {
const [email, setEmail] = useState("");
const [message, setMessage] = useState("");
const [loading, setLoading] = useState(false);
const notifySuccess = (message) => {
toast.success(message);
};
const notifyError = (error) => {
toast.error(error.message || "An error occurred");
};
const notifyLoading = () => {
toast.info("Sending verification link...");
};
const handleSubmit = async (e) => {
e.preventDefault();
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
if (!emailRegex.test(email)) {
notifyError("Please enter a valid email address");
return;
}
setLoading(true);
notifyLoading();
try {
const response = await axios.post(
"http://localhost:8080/password/forgot-password",
{ email }
);
setMessage(response.data.message);
notifySuccess(response.data.message);
} catch (error) {
console.error("Forgot password error:", error);
notifyError(error);
} finally {
setLoading(false);
}
};
const handleOpenInbox = () => {
const emailProviderUrl = "https://gmail.com/";
window.open(emailProviderUrl, "_blank");
};
const handleGoToLogin = () => {
window.location.href = "/";
};
return (
<>
<ToastContainer />
<div className="LoginPage">
<Container className="LoginPageContainer">
<Row className="PwPageContainer">
<Col md={12}>
<div className="PwPage">
<h1>Forgot Password</h1>
<p>
Enter your email address and we'll send you instructions on
how to reset your password
</p>
<form className="form-pw" onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
required
/>
<button type="submit" disabled={loading}>
{loading ? "Sending..." : "Send Verification Link"}
</button>
</form>
{message && (
<div className="ResponseDiv">
<p>{message}</p>
<div className="ResponseDivButton">
<button onClick={handleOpenInbox}>Open Gmail</button>
<button onClick={handleGoToLogin}>Back to Login</button>
</div>
</div>
)}
</div>
</Col>
</Row>
</Container>
</div>
</>
);
}
export default ForgetPwPage;

View File

@@ -0,0 +1,107 @@
import React, { useState, useEffect } from "react";
import { Container, Col, Row, Button, Spinner } from "react-bootstrap";
import axios from "axios";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
function HomePage(props) {
const notifyLoading = () => {
toast.info("Logging Out Successfull..");
};
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const handleLogout = () => {
axios
.get("http://localhost:8080/auth/logout", {
withCredentials: true,
})
.then(() => {
window.location.href = "/";
setUser(null);
localStorage.removeItem("user");
notifyLoading();
})
.catch((error) => {
console.error("Error logging out:", error);
});
};
const fetchUser = async () => {
const loggedInUser = localStorage.getItem("user");
if (loggedInUser) {
setUser(JSON.parse(loggedInUser));
setLoading(false);
} else {
try {
const response = await axios.get(
`http://localhost:8080/api/user/profile/`,
{
withCredentials: true,
}
);
setUser(response.data.user);
setLoading(false);
} catch (error) {
console.error("Error fetching user data:", error);
setLoading(false);
}
}
};
useEffect(() => {
fetchUser();
}, []);
return (
<>
<ToastContainer />
<div className="LoginPage">
<Container className="HomePageContainer ProfileContainer">
{loading ? (
<div className="loader">
<Spinner animation="border" role="status">
<span className="visually-hidden">Loading...</span>
</Spinner>
</div>
) : user ? (
<>
<Row>
<Col md={12}>
<h1>Welcome to MERN Auth App</h1>
</Col>
</Row>
<Row>
<Col md={12}>
<h1>Profile</h1>
<div className="profile-info">
<div className="profile-image">
<img src={user.profilePicture} alt="Profile" />
</div>
<div className="profile-details">
<p>Username: {user.username}</p>
<p>Email: {user.email}</p>
</div>
</div>
<Button onClick={handleLogout}>Logout</Button>
</Col>
</Row>
</>
) : (
<Row>
<Col md={12}>
<h1>Logging out...</h1>
</Col>
</Row>
)}
</Container>
</div>
</>
);
}
export default HomePage;

248
client/src/Pages/Login.jsx Normal file
View File

@@ -0,0 +1,248 @@
import React, { useEffect , useState } from "react";
import { Container, Col, Row } from "react-bootstrap";
import { FcGoogle } from "react-icons/fc";
import axios from "axios";
import md5 from "md5";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
function AuthPage() {
const [formData, setFormData] = useState({
username: "",
email: "",
password: "",
});
const [signin, setSignin] = useState(false);
const notifyError = (message) => {
toast.error(message);
};
function ToggleSign(event) {
event.preventDefault();
setSignin(!signin);
setFormData({
username: "",
email: "",
password: "",
});
}
function handleInputChange(event) {
const { name, value } = event.target;
setFormData((prevData) => ({
...prevData,
[name]: value,
}));
}
async function handleSubmit(event) {
event.preventDefault();
if (!formData.username.trim() && signin) {
notifyError("Username cannot be empty");
return;
}
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
if (!emailRegex.test(formData.email)) {
notifyError("Enter a valid email address");
return;
}
// Check password length
if (formData.password.length < 8) {
notifyError("Password must be at least 8 characters long");
return;
}
try {
const response = await axios.post(
`http://localhost:8080/api/${
!signin ? "login" : "register"
}`,
formData
);
const { user } = response.data;
delete user.password;
const gravatarUrl = `https://www.gravatar.com/avatar/${md5(
user.email
)}?d=identicon`;
user.profilePicture = gravatarUrl;
localStorage.setItem("user", JSON.stringify(user));
window.location.href = "/Home";
} catch (error) {
console.error("Authentication error:", error);
if (
error.response &&
error.response.status === 400 &&
error.response.data.message === "User already exists"
) {
notifyError("User already exists");
} else {
notifyError(error.response?.data.message || "An error occurred");
}
}
}
const handleGoogleLogin = (event) => {
event.preventDefault();
window.location.href =
"http://localhost:8080/auth/google";
};
return (
<>
<ToastContainer />
<div className="LoginPage">
<Container className={`LoginPageContainer ${signin ? "active" : ""}`}>
<Row>
<Col xs={12} md={6}>
<div className="form-container sign-up">
<SignUpForm
formData={formData}
handleInputChange={handleInputChange}
handleGoogleLogin={handleGoogleLogin}
handleSubmit={handleSubmit}
/>
</div>
<div className="form-container sign-in">
<SignInForm
formData={formData}
handleInputChange={handleInputChange}
handleGoogleLogin={handleGoogleLogin}
handleSubmit={handleSubmit}
/>
</div>
</Col>
<Col md={6}>
<TogglerContainer signin={signin} ToggleSign={ToggleSign} />
</Col>
</Row>
<Row>
<div className="OverlayAnimation">
{signin ? (
<div className="togglebtnlogin">
<button className="hidden" onClick={ToggleSign}>
Sign In
</button>
<span>Already Have an Account?</span>
</div>
) : (
<div className="togglebtnlogin">
<span>Don't have an account? Create one</span>
<button className="hidden" onClick={ToggleSign}>
Sign Up
</button>
</div>
)}
</div>
</Row>
</Container>
</div>
</>
);
}
function TogglerContainer(props) {
return (
<>
<div className="toggle-container">
<div className="toggle">
<div className="toggle-panel toggle-left">
<h1>Welcome to MERN Auth App</h1>
<p>Already Have an Account?</p>
<button className="hidden" onClick={props.ToggleSign}>
Sign In
</button>
</div>
<div className="toggle-panel toggle-right">
<h1>Welcome to MERN Auth App</h1>
<p>Don't have an account? Create one</p>
<button className="hidden" onClick={props.ToggleSign}>
Sign Up
</button>
</div>
</div>
</div>
</>
);
}
function SignUpForm(props) {
return (
<>
<form>
<h1>Create Account</h1>
<div className="Googlediv">
<button className="GoogleBtn" onClick={props.handleGoogleLogin}>
<FcGoogle className="icon" /> Sign up with Google
</button>
</div>
<span>or use your email for registration</span>
<input
type="text"
name="username"
value={props.formData.username}
onChange={props.handleInputChange}
placeholder="Name"
required
/>
<input
type="email"
name="email"
value={props.formData.email}
onChange={props.handleInputChange}
placeholder="Email"
required
/>
<input
type="password"
name="password"
value={props.formData.password}
onChange={props.handleInputChange}
placeholder="Password"
required
/>
<button onClick={props.handleSubmit}>Sign Up</button>
</form>
</>
);
}
function SignInForm(props) {
return (
<>
<form>
<h1>Sign In</h1>
<div>
<button className="GoogleBtn" onClick={props.handleGoogleLogin}>
<FcGoogle className="icon" /> Sign in with Google
</button>
</div>
<span>or use your email password</span>
<input
type="email"
name="email"
value={props.formData.email}
onChange={props.handleInputChange}
placeholder="Email"
required
/>
<input
type="password"
name="password"
value={props.formData.password}
onChange={props.handleInputChange}
placeholder="Password"
required
/>
<a href="/ForgetPw">Forget Your Password?</a>
<button onClick={props.handleSubmit}>Sign In</button>
</form>
</>
);
}
export default AuthPage;

View File

@@ -0,0 +1,87 @@
import React, { useState } from "react";
import { Container, Col, Row } from "react-bootstrap";
import { useParams } from "react-router-dom";
import axios from "axios";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
function ResetPwPage() {
const { token } = useParams();
const [newPassword, setNewPassword] = useState("");
const [message, setMessage] = useState("");
const notifySuccess = (message) => {
toast.success(message);
};
const notifyError = (error) => {
toast.error(error.message || "An error occurred");
};
const notifyLoading = () => {
toast.info("Sending Reset Request...");
};
const handleSubmit = async (e) => {
e.preventDefault();
if (newPassword.length < 8) {
toast.error("Password must be at least 8 characters long");
return;
}
notifyLoading();
try {
const response = await axios.post(
"http://:8080/password/reset-password",
{ resetToken: token, newPassword }
);
setMessage(response.data.message);
notifySuccess(response.data.message);
} catch (error) {
console.error(
"Reset password error:",
error.response ? error.response.data : error
);
notifyError(error);
}
};
const handleGoToLogin = () => {
window.location.href = "/";
};
return (
<>
<ToastContainer />
<div className="LoginPage">
<Container className="LoginPageContainer">
<Row className="PwPageContainer">
<Col md={12}>
<div className="PwPage">
<h1>Reset Password</h1>
<p>Enter your new password below</p>
<form className="form-pw" onSubmit={handleSubmit}>
<input
type="password"
value={newPassword}
onChange={(e) => setNewPassword(e.target.value)}
placeholder="New Password"
required
/>
<button type="submit">Reset Password</button>
</form>
{message && (
<div className="ResponseDiv">
<p>{message}</p>
<button onClick={handleGoToLogin}>Back to Login</button>
</div>
)}
</div>
</Col>
</Row>
</Container>
</div>
</>
);
}
export default ResetPwPage;

View File

@@ -0,0 +1,28 @@
import React from "react";
import { useNavigate } from "react-router-dom";
const Welcome = () => {
const navigate = useNavigate();
const handleRedirect = () => {
navigate("/AuthpPage");
};
return (
<div className="container text-center mt-5">
<div className="row justify-content-center">
<div className="col-md-6">
<h1 className="mb-4">Welcome Page</h1>
<button
onClick={handleRedirect}
className="btn btn-primary btn-lg"
>
SIGN IN / SIGN UP
</button>
</div>
</div>
</div>
);
};
export default Welcome;