Skip to content

Commit

Permalink
add verify route and update Login.jsx and Signup.jsx
Browse files Browse the repository at this point in the history
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
  • Loading branch information
piyush-gangrade committed May 11, 2024
1 parent 3fb45d2 commit f8f7e59
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 41 deletions.
11 changes: 11 additions & 0 deletions client/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -97,6 +98,16 @@ function App() {
</>
}
></Route>
{/* Add verify routes to verify otp */}
<Route
path="/verify"
element={
<>
<Navbar />
<VeifyOTP/>
</>
}
/>

{/* Enter routes from here Yash Suthar */}

Expand Down
24 changes: 13 additions & 11 deletions client/src/Components/Auth/Login.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down Expand Up @@ -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);
Expand Down
32 changes: 17 additions & 15 deletions client/src/Components/Auth/Signup.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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: "",
Expand Down Expand Up @@ -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);
}
Expand Down
107 changes: 107 additions & 0 deletions client/src/Components/Auth/VerifyOTP.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="flex flex-col items-center flex-wrap justify-center h-70-vh bg-gray-900">
<h1 className="text-white text-2xl mb-2">Please enter the One-Time Password</h1>
<h2 className="text-white mb-4">A One-Time Password has been sent to {email}</h2>
<input
type="number"
id="otp-code"
onChange={e => setOtpCode(e.target.value.slice(-6))}
value={otpCode}
className="my-6 outline-none hover:appearance-none text-center p-1 text-xl"
/>
<button onClick={handleSubmit} className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center mb-2">
Submit
</button>
</div>
)
}

export default VerifyOTP;
9 changes: 9 additions & 0 deletions client/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -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% {
Expand Down
3 changes: 3 additions & 0 deletions client/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ export default {
"Noto Color Emoji",
],
},
height: {
'70-vh': "70vh" //use for making full screen
}
},
},
plugins: ["flowbite/plugin"],
Expand Down
13 changes: 12 additions & 1 deletion server/.env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
TOKEN_KEY=yourSecretKey
MONGO_URL=mongodb://127.0.0.1:27017/ElectiveHub
PORT=4000
PORT=4000


OTP_SECRET=9WfKtNpGy3rVm2HlA8QwXc6o1Bd4Zs7E5uJiR

#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"
24 changes: 14 additions & 10 deletions server/Controllers/AuthController.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
Expand Down Expand Up @@ -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;
Expand All @@ -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}`
});
Expand All @@ -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"});
}

Expand All @@ -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})
}
}
10 changes: 6 additions & 4 deletions server/Models/UserModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -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()
// });



Expand Down

0 comments on commit f8f7e59

Please sign in to comment.