done
This commit is contained in:
parent
a2aa25ec47
commit
327ef99b6f
|
@ -127,3 +127,65 @@ export const showUser = async (req, res) => {
|
||||||
res.status(500).json({ message: "Internal servers error" });
|
res.status(500).json({ message: "Internal servers error" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//forgot password
|
||||||
|
|
||||||
|
export const forgotPassword = async (req, res) => {
|
||||||
|
const { email } = req.body;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const user = await UserModal.findOne({ email });
|
||||||
|
if (!user) {
|
||||||
|
return res.status(404).json({ message: "User not found" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const secrets = secret + user.password;
|
||||||
|
const token = jwt.sign({ email: user.email, id: user._id }, secrets, {
|
||||||
|
expiresIn: "5m",
|
||||||
|
});
|
||||||
|
user.resetToken = token;
|
||||||
|
user.resetTokenExpiration = Date.now() + 300000; // 5 minutes
|
||||||
|
await user.save();
|
||||||
|
res.status(200).send({ message: "Reset Email alert sent successfully" });
|
||||||
|
|
||||||
|
const url = `CLick on the link ${process.env.RETURN_URL}/users/resetpassword/${user._id}/${token}`;
|
||||||
|
|
||||||
|
await sendEmail(user.email, "Reset Email", url);
|
||||||
|
// res.json({ message: 'Password reset successful' });
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Forgot Password Error:", err);
|
||||||
|
res.status(500).json({ message: "Something went wrong" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// To reset password
|
||||||
|
|
||||||
|
export const resetPassword = async (req, res) => {
|
||||||
|
const { id, token } = req.params;
|
||||||
|
const { password } = req.body;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!password || password.trim() === "") {
|
||||||
|
return res.status(400).json({ message: "Password not entered" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = await UserModal.findOne({ _id: id });
|
||||||
|
if (!user) {
|
||||||
|
return res.json({ status: "User Not Exists!!" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the user's password and clear the reset token
|
||||||
|
user.password = await bcrypt.hash(password, 12);
|
||||||
|
// user.resetToken = undefined;
|
||||||
|
// user.resetTokenExpiration = undefined;
|
||||||
|
user.resetToken = token;
|
||||||
|
user.resetTokenExpiration = Date.now() + 300000; // 5 minutes
|
||||||
|
|
||||||
|
await user.save();
|
||||||
|
|
||||||
|
res.json({ message: "Password reset successful" });
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Password Reset Error:", err);
|
||||||
|
res.status(500).json({ message: "Something went wrong" });
|
||||||
|
}
|
||||||
|
};
|
|
@ -10,6 +10,9 @@ const userSchema = new mongoose.Schema({
|
||||||
termsconditions:{type: String,},
|
termsconditions:{type: String,},
|
||||||
userType:{ type: String, required: true },
|
userType:{ type: String, required: true },
|
||||||
verified: { type: Boolean, default: false },
|
verified: { type: Boolean, default: false },
|
||||||
|
id: { type: String },
|
||||||
|
resetToken: { type: String },
|
||||||
|
resetTokenExpiration: { type: String },
|
||||||
tokens:[
|
tokens:[
|
||||||
{
|
{
|
||||||
token:{
|
token:{
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
import express from "express";
|
import express from "express";
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
import { signup, signin, verifyUser, showUser } from "../controllers/user.js";
|
import { signup, signin, verifyUser, showUser, forgotPassword, resetPassword, } from "../controllers/user.js";
|
||||||
|
|
||||||
router.post("/signin", signin);
|
router.post("/signin", signin);
|
||||||
router.post("/signup", signup);
|
router.post("/signup", signup);
|
||||||
router.get('/:id/verify/:token/', verifyUser);
|
router.get('/:id/verify/:token/', verifyUser);
|
||||||
router.get('/:id', showUser);
|
router.get('/:id', showUser);
|
||||||
|
router.post("/forgotpassword", forgotPassword);
|
||||||
|
router.post("/resetpassword/:id/:token", resetPassword);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -27,7 +27,7 @@
|
||||||
<link rel="stylesheet" href="https://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css">
|
<link rel="stylesheet" href="https://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css">
|
||||||
<!-- fonts -->
|
<!-- fonts -->
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Raleway:wght@400;500;600;800&family=Sen:wght@400;700;800&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Raleway:wght@400;500;600;800&family=Sen:wght@400;700;800&display=swap" rel="stylesheet">
|
||||||
<script type="module" crossorigin src="/assets/index-CdnFdl54.js"></script>
|
<script type="module" crossorigin src="/assets/index-CTPhgL6j.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-CyAHZLBw.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-CyAHZLBw.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@ import Login from "./components/Login";
|
||||||
import Dashboard from "./components/Dashboard";
|
import Dashboard from "./components/Dashboard";
|
||||||
import PrivateRoute from "./components/PrivateRoute";
|
import PrivateRoute from "./components/PrivateRoute";
|
||||||
import VerifyUser from "./components/EmailVerify";
|
import VerifyUser from "./components/EmailVerify";
|
||||||
|
import ForgotPassword from "./components/ForgotPassword";
|
||||||
|
import ResetPassword from "./components/ResetPassword";
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
return (
|
return (
|
||||||
|
@ -27,6 +29,13 @@ const App = () => {
|
||||||
/>
|
/>
|
||||||
<Route path="/users/:id/verify/:token" element={<VerifyUser />} />
|
<Route path="/users/:id/verify/:token" element={<VerifyUser />} />
|
||||||
|
|
||||||
|
<Route path="/forgotpassword" element={<ForgotPassword />}></Route>
|
||||||
|
|
||||||
|
<Route
|
||||||
|
path="/users/resetpassword/:userId/:token"
|
||||||
|
element={<ResetPassword />}
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</Routes>
|
</Routes>
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
import { useState } from "react";
|
||||||
|
import axios from "axios";
|
||||||
|
import Navbar from "./Navbar";
|
||||||
|
import Footer from "../components/Footer";
|
||||||
|
|
||||||
|
|
||||||
|
const ForgotPassword = () => {
|
||||||
|
const [email, setEmail] = useState("");
|
||||||
|
const [message, setMessage] = useState("");
|
||||||
|
|
||||||
|
const BASE_URL = import.meta.env.VITE_REACT_APP_SECRET;
|
||||||
|
|
||||||
|
const handleResetPassword = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.post(`${BASE_URL}/users/forgotpassword`, {
|
||||||
|
email,
|
||||||
|
});
|
||||||
|
|
||||||
|
setMessage(response.data.message);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Forgot Password Error:", error);
|
||||||
|
setMessage(error.response.data.message);
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Navbar />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<section className="card mb-0 vh-100">
|
||||||
|
<div className="container py-10 h-100">
|
||||||
|
<div className="row d-flex align-items-center justify-content-center h-100">
|
||||||
|
<div className="col-md-10 col-lg-5 col-xl-5 offset-xl-1 card mb-10">
|
||||||
|
<h3 className="card-header" style={{ color: "#F74B02" }}>
|
||||||
|
<span className="pi pi-lock" style={{ color: "#067ADC" }}>
|
||||||
|
{" "}
|
||||||
|
</span>{" "}
|
||||||
|
{" "}
|
||||||
|
Forgot{" "}
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
color: "#067ADC",
|
||||||
|
marginRight: "3px",
|
||||||
|
marginLeft: "3px",
|
||||||
|
fontWeight: "bold",
|
||||||
|
fontSize: "30px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
/
|
||||||
|
</span>{" "}
|
||||||
|
Change Password
|
||||||
|
</h3>
|
||||||
|
<br />
|
||||||
|
<p className="card-title text-center">
|
||||||
|
Enter your email address to receive a password reset link:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
className="container d-flex align-items-center justify-content-center vh-50"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
value={email}
|
||||||
|
className="form-control"
|
||||||
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
|
placeholder="Enter your email"
|
||||||
|
style={{ width: "80%", marginBottom: "15px" }}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
className="btn btn-primary"
|
||||||
|
style={{
|
||||||
|
width: "35%",
|
||||||
|
border: "1px solid #FFFFFF",
|
||||||
|
borderRadius: "10px",
|
||||||
|
color: "#FFFFFF",
|
||||||
|
}}
|
||||||
|
onClick={handleResetPassword}
|
||||||
|
>
|
||||||
|
Reset Password
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
style={{ color: "#067ADC" }}
|
||||||
|
className="card-title text-center"
|
||||||
|
>
|
||||||
|
{message}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ForgotPassword;
|
|
@ -1,4 +1,5 @@
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
|
import { NavLink } from "react-router-dom";
|
||||||
import Footer from "./Footer";
|
import Footer from "./Footer";
|
||||||
import Navbar from "./Navbar";
|
import Navbar from "./Navbar";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
|
@ -164,12 +165,16 @@ const Login = () => {
|
||||||
<div className="d-flex gap-2 gap-md-4 flex-column flex-md-row justify-content-md-end mt-4">
|
<div className="d-flex gap-2 gap-md-4 flex-column flex-md-row justify-content-md-end mt-4">
|
||||||
<p className="m-0 text-secondary text-center">
|
<p className="m-0 text-secondary text-center">
|
||||||
Don't have an account?{" "}
|
Don't have an account?{" "}
|
||||||
<a
|
<NavLink to="/register" className="link-primary text-decoration-none">
|
||||||
href="#!"
|
|
||||||
className="link-primary text-decoration-none"
|
|
||||||
>
|
|
||||||
Register
|
Register
|
||||||
</a>
|
</NavLink>
|
||||||
|
|
||||||
|
|
||||||
|
<NavLink to="/forgotpassword" className="nav-link">
|
||||||
|
Forgot Password
|
||||||
|
</NavLink>
|
||||||
|
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import axios from "axios";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
import Navbar from "./Navbar";
|
||||||
|
import Footer from "./Footer";
|
||||||
|
|
||||||
|
const ResetPassword = () => {
|
||||||
|
const { userId, token } = useParams();
|
||||||
|
const [password, setPassword] = useState("");
|
||||||
|
const [confirmPassword, setConfirmPassword] = useState("");
|
||||||
|
const [message, setMessage] = useState("");
|
||||||
|
|
||||||
|
const BASE_URL = import.meta.env.VITE_REACT_APP_SECRET;
|
||||||
|
|
||||||
|
const handleResetPassword = async () => {
|
||||||
|
try {
|
||||||
|
if (!password || password.trim() === "") {
|
||||||
|
setMessage("Password not entered");
|
||||||
|
toast.error("Password not entered"); // Use toast.error instead of toast.success
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await axios.post(
|
||||||
|
`${BASE_URL}/users/resetpassword/${userId}/${token}`,
|
||||||
|
{ userId, token, password }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (password !== confirmPassword) {
|
||||||
|
setMessage("Passwords do not match.");
|
||||||
|
toast.error("Passwords do not match.");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
setMessage("Password reset successfull");
|
||||||
|
toast.success(response.data.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Reset Password Error:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Clear any existing toasts when the component mounts
|
||||||
|
toast.dismiss();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Navbar />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<section className="card mb-0 vh-100">
|
||||||
|
<div className="container py-10 h-100">
|
||||||
|
<div className="row d-flex align-items-center justify-content-center h-100">
|
||||||
|
<div className="col-md-10 col-lg-5 col-xl-5 offset-xl-1 card mb-10">
|
||||||
|
<h2 className="card-header" style={{ color: '#F74B02' }}>
|
||||||
|
<span className="pi pi-lock-open" style={{ color: '#067ADC' }}> </span> {" "}
|
||||||
|
Reset Password
|
||||||
|
</h2>
|
||||||
|
<br />
|
||||||
|
<p className="card-title text-center" style={{ color: '#F74B02' }}>
|
||||||
|
Enter your new password:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<input
|
||||||
|
className="form-control vh-10"
|
||||||
|
type="password"
|
||||||
|
value={password}
|
||||||
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
|
placeholder="Enter your new password"
|
||||||
|
style={{ display: "flex", gap: "35px" }}
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<input
|
||||||
|
className="form-control"
|
||||||
|
type="password"
|
||||||
|
value={confirmPassword}
|
||||||
|
onChange={(e) => setConfirmPassword(e.target.value)}
|
||||||
|
placeholder="Confirm your new password"
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<button onClick={handleResetPassword} className="btn btn-primary" style={{
|
||||||
|
width: "35%" }}>
|
||||||
|
Reset Password
|
||||||
|
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<p style={{ color: "#067ADC" }} className="card-title text-center">
|
||||||
|
{message}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<Footer />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ResetPassword;
|
|
@ -21,7 +21,7 @@ export const verifyEmail = createAsyncThunk(
|
||||||
const response = await api.verifyEmail(id, token, data);
|
const response = await api.verifyEmail(id, token, data);
|
||||||
return response.data.message;
|
return response.data.message;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return rejectWithValue("Error verifying email");
|
return rejectWithValue(error.response.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -14,6 +14,7 @@ export default defineConfig({
|
||||||
|
|
||||||
'/users/signup': 'http://67.225.129.127:3002/',
|
'/users/signup': 'http://67.225.129.127:3002/',
|
||||||
'/users/signin': 'http://67.225.129.127:3002/',
|
'/users/signin': 'http://67.225.129.127:3002/',
|
||||||
|
'/users/forgotpassword': 'http://67.225.129.127:3002/',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue