Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented the Forgot Password Functionality #154

Closed
wants to merge 43 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
ddd9617
forgot password commit
RithikaSundaram Jun 2, 2024
f08c1ce
resolved commit
RithikaSundaram Jun 2, 2024
18db488
resolve commit
RithikaSundaram Jun 2, 2024
9176dc9
first commit
RithikaSundaram Jun 2, 2024
22bab40
second commit
RithikaSundaram Jun 2, 2024
08262de
third commit
RithikaSundaram Jun 2, 2024
485818f
index commit
RithikaSundaram Jun 2, 2024
76c711e
indexjs commit
RithikaSundaram Jun 2, 2024
b848b44
indexjs commit
RithikaSundaram Jun 2, 2024
972f13d
in commit
RithikaSundaram Jun 2, 2024
ec0fe99
last commit
RithikaSundaram Jun 2, 2024
77ffc98
final commit
RithikaSundaram Jun 2, 2024
db7f403
controller commit
RithikaSundaram Jun 2, 2024
3650858
control commit
RithikaSundaram Jun 2, 2024
0492538
finals commit
RithikaSundaram Jun 2, 2024
564784b
login route updated commit
RithikaSundaram Jun 2, 2024
f2ad43f
app commit
RithikaSundaram Jul 19, 2024
f2c992a
app commit
RithikaSundaram Jul 19, 2024
876554e
msg commit
RithikaSundaram Jul 19, 2024
479ccc8
one commit
RithikaSundaram Jul 19, 2024
dd9ec47
conflict commit
RithikaSundaram Jul 19, 2024
57407da
second commit
RithikaSundaram Jul 19, 2024
d88811f
third commit
RithikaSundaram Jul 19, 2024
cb6bd02
fourth commit
RithikaSundaram Jul 19, 2024
5ffe2e8
schema commit
RithikaSundaram Jul 19, 2024
31b07c1
app final commit
RithikaSundaram Jul 19, 2024
d2fc3a7
app finals commit
RithikaSundaram Jul 19, 2024
47e37d7
app final one commit
RithikaSundaram Jul 19, 2024
966b1d6
login final commit
RithikaSundaram Jul 20, 2024
298d49b
login final one commit
RithikaSundaram Jul 20, 2024
7d4c273
login second commit
RithikaSundaram Jul 20, 2024
e4c9021
login final added commit
RithikaSundaram Jul 20, 2024
49e041f
login final fourth commit
RithikaSundaram Jul 20, 2024
a84e8f8
controller final one commit
RithikaSundaram Jul 20, 2024
b0e33bd
control second commit
RithikaSundaram Jul 20, 2024
6b8575e
control third commit
RithikaSundaram Jul 20, 2024
3852d64
control fourth commit
RithikaSundaram Jul 20, 2024
723072e
controller fifth commit
RithikaSundaram Jul 20, 2024
7f07fca
controller sixth commit
RithikaSundaram Jul 20, 2024
c785be7
index final commit
RithikaSundaram Jul 20, 2024
c27ac5d
index last commit
RithikaSundaram Jul 20, 2024
f6c32e4
index final one commit
RithikaSundaram Jul 20, 2024
78179ab
env commit
RithikaSundaram Jul 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
MONGO_URL=
PORT=8080
MONGO_URL=mongodb://localhost:27017
PORT=8080
REFRESH_TOKEN_COOKIE_EXPIRE=30
REFRESH_TOKEN_SECRET=XYZ
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"editor.formatOnSave": false
}
67 changes: 45 additions & 22 deletions client/src/App.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,67 @@

import "./App.css";
// import {Outlet} from "react-router-dom";
import React, { useState, useEffect } from 'react';
import { Navbar, Footer } from './Components/index.js';
import { ProfilePage, Product } from './Components/index';
import LoginPage from './Pages/LoginPage.jsx';
import SignUpPage from './Pages/SignUpPage.jsx';
import Cart from './Pages/Cart.jsx';
import Profile from "./Pages/Profile.jsx";
import Orders from './Pages/Orders.jsx';
import Wishlist from './Pages/Wishlist.jsx';
import HomePage from './Pages/Home.jsx';
import Shop from "./Pages/Shop.jsx";
import { Toast } from "./Toast/Toast.js";

import { BrowserRouter as Router, Routes, Route} from 'react-router-dom';
import Contact from "./Pages/Contact.jsx";
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import './Animations.css';
import FAQ from "./Pages/Faq.jsx";

function App() {
const [darkMode, setDarkMode] = useState(false);

const toggleDarkMode = () => {
setDarkMode(!darkMode);
};

useEffect(() => {
if (darkMode) {
document.body.style.backgroundColor = '#121212';
document.body.style.color = 'black';
} else {
document.body.style.backgroundColor = 'white';
document.body.style.color = 'black';
}
}, [darkMode]);

const appStyle = {
backgroundColor: darkMode ? '#333' : '#f4f4f4',
padding: '20px',
borderRadius: '8px',
};

function App() {
return (
<>

<Router>
<div className="App">
<Navbar/>
<Routes>
<Route path="/" exact element={<HomePage/>} />
<Route path="/shop" exact element={<Shop/>} />
<Route path="/shop/:id" element={<Product/>} />
<Route path="/login" element={<LoginPage/>} />
<Route path="/signup" element={<SignUpPage/>} />
<Route path="/wishlist" element={<Wishlist/>} />
<Route path="/cart" element={<Cart/>} />
<Route path="/orders" element={<Orders/>} />
</Routes>
<Toast position="bottom-right"/>
<Footer/>
</div>
</Router>

<Router>
<div className="App" style={appStyle}>
<Navbar darkMode={darkMode} toggleDarkMode={toggleDarkMode} />
<Routes>
<Route path="/" exact element={<HomePage darkMode={darkMode} />} />
<Route path="/shop" exact element={<Shop />} />
<Route path="/shop/:id" element={<Product />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/signup" element={<SignUpPage />} />
<Route path="/wishlist" element={<Wishlist />} />
<Route path="/cart" element={<Cart />} />
<Route path="/orders" element={<Orders />} />
<Route path="/contactus" element={<Contact />} />
<Route path="/faqs" element={<FAQ/>}/>
</Routes>
<Toast position="bottom-right" />
<Footer />
</div>
</Router>
</>
);
}
Expand Down
53 changes: 53 additions & 0 deletions client/src/Pages/ForgotPassword.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// ForgotPasswordPage.jsx
import React, { useState } from "react";
import { Container, Typography, TextField, Button } from "@mui/material";
import axios from "axios";

const ForgotPasswordPage = () => {
const [email, setEmail] = useState("");
const [message, setMessage] = useState("");

const handleSubmit = async (e) => {
e.preventDefault();

try {
const response = await axios.post(
"http://localhost:8080/auth/password/forgot",
{ email }
);
setMessage(response.data.message);
} catch (error) {
setMessage(error.response.data.message);
}
};

return (
<Container maxWidth="xl">
<div style={{ marginTop: "100px", marginBottom: "180px" }}>
<Typography variant="h5" align="center" gutterBottom>
Forgot Password
</Typography>
<form onSubmit={handleSubmit} style={{ textAlign: "center" }}>
<TextField
label="Email"
fullWidth
variant="outlined"
value={email}
onChange={(e) => setEmail(e.target.value)}
margin="normal"
/>
<Button variant="contained" type="submit" sx={{ mt: 2 }}>
Submit
</Button>
</form>
{message && (
<Typography color="primary" align="center">
{message}
</Typography>
)}
</div>
</Container>
);
};

export default ForgotPasswordPage;
88 changes: 59 additions & 29 deletions client/src/Pages/LoginPage.jsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,68 @@
"use client";

import React, { useState } from "react";
import TextField from "@mui/material/TextField";
import Button from "@mui/material/Button";
import IconButton from "@mui/material/IconButton"; // Import IconButton
import VisibilityIcon from "@mui/icons-material/Visibility"; // Import VisibilityIcon
import VisibilityOffIcon from "@mui/icons-material/VisibilityOff"; // Import VisibilityOffIcon
import { Box, Container, Grid, Typography } from "@mui/material";
import Lottie from "lottie-react";
import loginAnimation from '../Lottie-animation/loginAnimation.json'
import loginAnimation from "../Lottie-animation/loginAnimation.json";
import axios from "axios";
import toast, { Toaster } from "react-hot-toast"
import toast, { Toaster } from "react-hot-toast";
import { useNavigate } from "react-router-dom";
import { useAuth } from "../Context/AuthContext";
import { useToast } from "../Context/ToastContext";

const LoginPage = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState(""); //state to store error message
const { setUserLoggedIn }= useAuth()
const { showToast } = useToast()
const [showPassword, setShowPassword] = useState(false); // State to track password visibility
const [error, setError] = useState("");
const { setUserLoggedIn } = useAuth();
const { showToast } = useToast();
let navigate = useNavigate();

// handle Submit function
const handleSubmit = async (e) => {
e.preventDefault();

try {
const response = await axios.post("http://localhost:8080/customer/login", { email, password })
const response = await axios.post("http://localhost:8080/customer/login", {
email,
password,
});
console.log(response.data);
toast.success("login sucess")
// reset form and err msg on sucess
toast.success("login success");
setEmail("");
setPassword("");
setError("");
const { token } = response.data;
localStorage.setItem('token', token);
localStorage.setItem("token", token);
setUserLoggedIn(true);
showToast("success","","Logged in successfully");
navigate('/', { replace: true });
showToast("success", "", "Logged in successfully");
navigate("/", { replace: true });
} catch (err) {
setError(err.response.data.message);//set error message received from backend
setError(err.response.data.message);
}
};

// Function to toggle password visibility
const togglePasswordVisibility = () => {
setShowPassword(!showPassword);
};

}
return (
<Container maxWidth="xl">
<div style={{ marginTop: "100px", marginBottom: "180px" }}>
<Toaster/>
<Grid container spacing={2} sx={{ justifyContent: 'center' }}>
<Toaster />
<Grid container spacing={2} sx={{ justifyContent: "center" }}>
<Grid item xs={12} md={6}>
<Box sx={{ display: { xs: "none", md: "block" } }}>
<Lottie animationData={loginAnimation} style={{ height: '500px' }} className="fromLeft" />
<Lottie
animationData={loginAnimation}
style={{ height: "500px" }}
className="fromLeft"
/>
</Box>
</Grid>
<Grid
Expand All @@ -60,7 +75,6 @@ const LoginPage = () => {
justifyContent: "center",
}}
>

<form onSubmit={handleSubmit} className="fromRight">
<Typography variant="h5" align="center" gutterBottom>
Login
Expand All @@ -73,16 +87,28 @@ const LoginPage = () => {
onChange={(e) => setEmail(e.target.value)}
margin="normal"
/>
<TextField
fullWidth
label="Password"
type="password"
variant="outlined"
value={password}
onChange={(e) => setPassword(e.target.value)}
margin="normal"
/>
{error && <Typography color="error" align="center">{error}</Typography>}
<Box sx={{ position: "relative", display: "flex", alignItems: "center" }}>
<TextField
fullWidth
label="Password"
type={showPassword ? "text" : "password"} // Set input type dynamically
variant="outlined"
value={password}
onChange={(e) => setPassword(e.target.value)}
margin="normal"
/>
<IconButton
onClick={togglePasswordVisibility}
sx={{ position: "absolute", right: "10px", top: "50%", transform: "translateY(-50%)" }}
>
{showPassword ? <VisibilityIcon /> : <VisibilityOffIcon />}
</IconButton>
</Box>
{error && (
<Typography color="error" align="center">
{error}
</Typography>
)}
<Button
variant="contained"
type="submit"
Expand All @@ -94,6 +120,10 @@ const LoginPage = () => {
>
Login
</Button>
{/* Forgot Password Link */}
<Typography align="center" sx={{ mt: 2, mr: 2 }}>
<Link to="/password/forgot">Forgot Password?</Link>
</Typography>
<Typography align="center" sx={{ mt: 2, mr: 2 }}>
Don't have an account? <a href="/signup">Sign up</a>
</Typography>
Expand Down
91 changes: 91 additions & 0 deletions client/src/Pages/ResetPassword.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import React, { useState } from "react";
import axios from "axios";
import { useParams } from "react-router-dom";

const ResetPassword = () => {
const { token } = useParams();
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [message, setMessage] = useState("");
const [loading, setLoading] = useState(false);

const inputStyle = {
width: "100%",
padding: "10px",
marginBottom: "10px",
border: "1px solid #ccc",
borderRadius: "4px",
};

const buttonStyle = {
width: "100%",
padding: "10px",
backgroundColor: "#007bff",
color: "#fff",
border: "none",
borderRadius: "4px",
cursor: "pointer",
};

const handleSubmit = async (e) => {
e.preventDefault();
if (password !== confirmPassword) {
setMessage("Passwords do not match");
return;
}
setLoading(true);
setMessage("");
try {
await axios.put(`http://localhost:8080/auth/password/reset/${token}`, {
password,
});
setMessage("Password updated successfully");
} catch (error) {
setMessage(
error.response.data.message ||
"Error resetting password. Please try again."
);
} finally {
setLoading(false);
}
};

return (
<div
style={{
maxWidth: "400px",
margin: "0 auto",
padding: "20px",
border: "1px solid #ccc",
borderRadius: "8px",
backgroundColor: "#f9f9f9",
}}
>
<h2>Reset Password</h2>
<form onSubmit={handleSubmit} style={{ marginBottom: "20px" }}>
<input
style={inputStyle}
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Enter new password"
required
/>
<input
style={inputStyle}
type="password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
placeholder="Confirm new password"
required
/>
<button style={buttonStyle} type="submit" disabled={loading}>
{loading ? "Resetting..." : "Reset Password"}
</button>
</form>
{message && <p>{message}</p>}
</div>
);
};

export default ResetPassword;
Loading