From 2ff5acc6073a9aaf8127c5cf89b1eba68c95b4c7 Mon Sep 17 00:00:00 2001 From: piyush-gangrade Date: Sat, 11 May 2024 17:40:14 +0530 Subject: [PATCH] add verify route and update Login.jsx and Signup.jsx Add VerifyOTP.jsx and update Login.jsx and SignUp.jsx so that after login and signup, the user navigates to the verify route, and an OTP is sent to the user's email. After entering the OTP, the user will be logged in --- client/src/App.jsx | 11 +++ client/src/Components/Auth/Login.jsx | 24 ++--- client/src/Components/Auth/Signup.jsx | 32 +++---- client/src/Components/Auth/VerifyOTP.jsx | 107 +++++++++++++++++++++++ client/src/index.css | 9 ++ client/tailwind.config.js | 3 + server/.env.example | 13 ++- server/Controllers/AuthController.js | 24 ++--- server/Models/UserModel.js | 10 ++- 9 files changed, 192 insertions(+), 41 deletions(-) create mode 100644 client/src/Components/Auth/VerifyOTP.jsx diff --git a/client/src/App.jsx b/client/src/App.jsx index d376822..8ea8080 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -10,6 +10,7 @@ import Navbar from "./Components/Navbar"; import Footer from "./Components/Footer"; import Login from "./Components/Auth/Login"; import Signup from "./Components/Auth/Signup"; +import VeifyOTP from "./Components/Auth/VerifyOTP";//for OTP verification import Syllbus from "./Components/Syllbus/Syllbus"; import SujectInfo from "./Components/SyllbusInfo/SyllbusInfo"; import ProtectedRoutes from "./Pages/ProtectedRoutes"; @@ -97,6 +98,16 @@ function App() { } > + {/* Add verify routes to verify otp */} + + + + + } + /> {/* Enter routes from here Yash Suthar */} diff --git a/client/src/Components/Auth/Login.jsx b/client/src/Components/Auth/Login.jsx index 5b8928e..3859071 100644 --- a/client/src/Components/Auth/Login.jsx +++ b/client/src/Components/Auth/Login.jsx @@ -9,8 +9,8 @@ import userImg from "../../assets/images/user.webp"; import { toast } from "react-toastify"; const Login = () => { - const cookies = new Cookies(); - const { login } = useContext(AuthContext); + // const cookies = new Cookies(); + // const { login } = useContext(AuthContext); const navigate = useNavigate(); const [inputValue, setInputValue] = useState({ @@ -44,20 +44,22 @@ const Login = () => { } ); - if (response) { - console.log(response.data.token); - login(response.data.token); + // if (response) { + console.log(response.data); + // login(response.data.token); - cookies.set("TOKEN", response.data.token, { - path: "/", - }); - } - console.log(cookies.get("TOKEN")); + // cookies.set("TOKEN", response.data.token, { + // path: "/", + // }); + // } + // console.log(cookies.get("TOKEN")); const { success, message } = response.data; + //if user login successfully then navigate to verify page if (success) { - navigate("/Home"); + navigate("/verify", {state: {email: inputValue.email}}); + // navigate("/Home"); } else { alert(message.message); console.log(message); diff --git a/client/src/Components/Auth/Signup.jsx b/client/src/Components/Auth/Signup.jsx index 0ee6e2f..16dfc46 100644 --- a/client/src/Components/Auth/Signup.jsx +++ b/client/src/Components/Auth/Signup.jsx @@ -8,8 +8,8 @@ import userImg from "../../assets/images/user.webp"; import { toast } from "react-toastify"; const Signup = () => { - const cookies = new Cookies(); - const { login } = useContext(AuthContext); + // const cookies = new Cookies(); + // const { login } = useContext(AuthContext); const navigate = useNavigate(); const [inputValue, setInputValue] = useState({ email: "", @@ -55,21 +55,23 @@ const Signup = () => { } ); - if (response) { - console.log(response.data.token); - cookies.set("TOKEN", response.data.token, { - path: "/", - }); - } - console.log(cookies.get("TOKEN")); - + // if (response) { + // cookies.set("TOKEN", response.data.token, { + // path: "/", + // }); + // } + // console.log(cookies.get("TOKEN")); + // console.log(response.data); + const { success, message } = response.data; + //if user login successfully then navigate to verify page if (success) { - login(response.data.token); - cookies.set("TOKEN", response.data.token, { - path: "/", - }); - navigate("/Home"); + console.log(message) + // login(response.data.token); + // cookies.set("TOKEN", response.data.token, { + // path: "/", + // }); + navigate("/verify", {state: {email: inputValue.email}}); } else { console.log(message); } diff --git a/client/src/Components/Auth/VerifyOTP.jsx b/client/src/Components/Auth/VerifyOTP.jsx new file mode 100644 index 0000000..61af2ff --- /dev/null +++ b/client/src/Components/Auth/VerifyOTP.jsx @@ -0,0 +1,107 @@ +import React, { useContext, useEffect, useState } from "react"; +import axios from "axios"; +import { toast } from "react-toastify"; +import Cookies from "universal-cookie"; +import { useLocation, useNavigate } from "react-router-dom"; +import { AuthContext } from "./AuthContext"; + +const VerifyOTP = () => { + const cookies = new Cookies(); + const location = useLocation(); + const navigate = useNavigate(); + const { login } = useContext(AuthContext); + const [otpCode, setOtpCode] = useState(""); + const [email, setEmail] = useState(null); + + //send otp to users email function + const sendEmail = async(email)=>{ + try{ + const res = await axios.post( + `${import.meta.env.VITE_API_URL}/auth/send-otp`, + { + email: email + } + ) + + console.log(res) + } + catch(err){ + console.log(err); + } + } + + + useEffect(()=>{ + //send otp + async function send(){ + //check that it access only after login and signup + if(location.state){ + setEmail(location.state.email) + email && sendEmail(email); + } + else{ + // + navigate("/", {replace: true}); + } + } + send(); + },[email]) + + const handleSubmit = async (e) => { + e.preventDefault(); + + if (otpCode.length < 6) { + toast.error("Please enter the otp"); + return; + } + + try { + const res = await axios.post( + `${import.meta.env.VITE_API_URL}/auth/verify-otp`, + { + email, + otpCode + } + ); + + console.log(res); + + const { success, message, token } = res.data; + if (success) { + console.log(message) + login(token); + cookies.set("TOKEN", token, { + path: "/", + }); + navigate("/Home"); + } else { + console.log(message); + toast.error("Invalid OTP") + } + } + catch (err) { + toast.error("Invalid OTP") + console.log(err) + } + + } + + return ( +
+

Please enter the One-Time Password

+

A One-Time Password has been sent to {email}

+ setOtpCode(e.target.value.slice(-6))} + value={otpCode} + className="my-6 outline-none hover:appearance-none text-center p-1 text-xl" + /> + +
+ ) +} + +export default VerifyOTP; \ No newline at end of file diff --git a/client/src/index.css b/client/src/index.css index 2e5915d..1c25665 100644 --- a/client/src/index.css +++ b/client/src/index.css @@ -4,6 +4,15 @@ @tailwind components; @tailwind utilities; +/* for removing arrow from input field */ +@layer base { + input[type="number"]::-webkit-inner-spin-button, + input[type="number"]::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; + } +} + @keyframes bounce-slow { 0%, 100% { diff --git a/client/tailwind.config.js b/client/tailwind.config.js index 1b65e2f..64c7d6f 100644 --- a/client/tailwind.config.js +++ b/client/tailwind.config.js @@ -58,6 +58,9 @@ export default { "Noto Color Emoji", ], }, + height: { + '70-vh': "70vh" //use for making full screen + } }, }, plugins: ["flowbite/plugin"], diff --git a/server/.env.example b/server/.env.example index d288088..26b3444 100644 --- a/server/.env.example +++ b/server/.env.example @@ -1,3 +1,14 @@ TOKEN_KEY=yourSecretKey MONGO_URL=mongodb://127.0.0.1:27017/ElectiveHub -PORT=4000 \ No newline at end of file +PORT=4000 + + +OTP_SECRET=yourOtpSecret + +#email variables +EMAIL_HOST=smtp.gmail.com +EMAIL_SERVICE=gmail +EMAIL_POST=587 +EMAIL_SECURE=false +USER_EMAIL="add offical email for sending code" +USER_PASS="add password" \ No newline at end of file diff --git a/server/Controllers/AuthController.js b/server/Controllers/AuthController.js index 3f69700..f3c3451 100644 --- a/server/Controllers/AuthController.js +++ b/server/Controllers/AuthController.js @@ -11,7 +11,10 @@ module.exports.Signup = async (req, res, next) => { if (existingUser) { return res.json({ message: "User already exists" }); } - const user = await User.create({ email, password, username,role}); + + //hash password only when new user created + const hashPassword = await bcrypt.hash(password, 12); + const user = await User.create({ email, password:hashPassword, username,role}); res .status(201) .json({ message: "User signed in successfully", success: true }); @@ -45,9 +48,10 @@ module.exports.Login = async (req, res, next) => { module.exports.sendOTP = async(req, res)=>{ try{ - const {userId} = req.body; - const user = await User.findById(userId); + const {email} = req.body; + const user = await User.findOne({email}); + //generate otp from otplib const otp = authenticator.generate(process.env.OTP_SECRET); user.otpToken = otp; @@ -56,7 +60,7 @@ module.exports.sendOTP = async(req, res)=>{ await user.save(); await sendEmail({ - email: user.email, + email: email, subject: "OTP Verification", message: `Your One-Time Password(OTP) is: ${otp}` }); @@ -65,18 +69,18 @@ module.exports.sendOTP = async(req, res)=>{ } catch(err){ console.error(err); - return res.status(500).json({error: "Something is wrong. Please try after some time."}); + return res.status(500).json({error: "Something is wrong. Please try after some time.", success: false}); } } module.exports.verifyOTP = async(req, res)=>{ try{ - const {userId, otp} = req.body; - const user = await User.findById(userId); + const {email, otpCode} = req.body; + const user = await User.findOne({email}); const currentTime = Date.now(); //check otp is valid or not - if(otp !== user.otpToken || currentTime > user.optExpiry){ + if(otpCode !== user.otpToken || currentTime > user.optExpiry){ return res.status(400).json({error: "Invalid OTP"}); } @@ -87,10 +91,10 @@ module.exports.verifyOTP = async(req, res)=>{ }); res .status(200) - .json({ message: "OTP verified", success: true, token }); + .json({ message: "OTP verified", success: true, token: token }); } catch(err){ console.error(err); - return res.status(500).json({error: "Something is wrong. Please try after some time."}) + return res.status(500).json({error: "Something is wrong. Please try after some time.", success: false}) } } \ No newline at end of file diff --git a/server/Models/UserModel.js b/server/Models/UserModel.js index 9fdbb85..7d26e57 100644 --- a/server/Models/UserModel.js +++ b/server/Models/UserModel.js @@ -33,10 +33,12 @@ const userSchema = new mongoose.Schema({ }, }); -userSchema.pre("save", async function (next) { - this.password = await bcrypt.hash(this.password, 12); - next() -}); +//Its change password every time + +// userSchema.pre("save", async function (next) { +// this.password = await bcrypt.hash(this.password, 12); +// next() +// });