diff --git a/backend/controllers/authController.js b/backend/controllers/authController.js index db32153..ae255a0 100644 --- a/backend/controllers/authController.js +++ b/backend/controllers/authController.js @@ -13,6 +13,7 @@ import { setAuthCookie, clearAuthCookie } from '../helpers/cookieHelpers.js'; import { registerValidation, loginValidation, validate } from '../middleware/validationMiddleware.js'; import { protect } from '../middleware/authMiddleware.js'; // Import authMiddleware +const pendingUsers = new Map(); // Register export const register = [ registerValidation, @@ -34,28 +35,15 @@ export const register = [ try { const hashedPassword = await bcrypt.hash(password, 10); - const user = new userModel({ name, email, password: hashedPassword }); - await user.save(); - - const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '7d' }); - setAuthCookie(res, token); - - // Send Welcome Email - const welcomeMailOptions = { - from: process.env.SENDER_EMAIL, - to: email, - subject: 'Welcome to PlantZ', - text: `Welcome to PlantZ website. Your account has been created with email id: ${email}`, - }; - - await transporter.sendMail(welcomeMailOptions); - - // Send OTP Email const { otp, hashedOtp } = await generateAndHashOTP(); - user.verifyOtp = hashedOtp; - user.verifyOtpExpireAt = Date.now() + 24 * 60 * 60 * 1000; - await user.save(); + pendingUsers.set(email, { + name, + email, + password: hashedPassword, + verifyOtp: hashedOtp, + verifyOtpExpireAt: Date.now() + 24 * 60 * 60 * 1000 + }); const otpMailOption = { from: process.env.SENDER_EMAIL, @@ -64,9 +52,12 @@ export const register = [ html: EMAIL_VERIFY_TEMPLATE.replace('{{otp}}', otp).replace('{{email}}', email), }; - await transporter.sendMail(otpMailOption); + transporter.sendMail(otpMailOption) + .then(() => console.log('OTP email sent')) + .catch((err) => console.error('Error sending OTP email:', err)); - sendSuccess(res, {}, 'User registered successfully and OTP sent to email', 201); + sendSuccess(res, {}, 'OTP sent to email. Please verify your account.', 201); + } catch (error) { console.error('Registration error:', error); if (error.code === 11000) { @@ -89,7 +80,6 @@ export const login = [ if (!user) { return sendError(res, 'Invalid email or password', 400); } - const isMatch = await bcrypt.compare(password, user.password); if (!isMatch) { return sendError(res, 'Invalid email or password', 400); @@ -98,7 +88,7 @@ export const login = [ const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '7d' }); setAuthCookie(res, token); - // Include a message and user data in the response + sendSuccess(res, { user: { _id: user._id, @@ -165,35 +155,58 @@ export const sendVerifyOtp = [ ]; // Verify Email using OTP -export const verifyEmail = [ - protect, - asyncHandler(async (req, res) => { - const { otp } = req.body; - const userId = req.user._id; // Get userId from req.user - - if (!otp) { - return sendError(res, 'Missing OTP', 400); +export const verifyEmail = [asyncHandler(async (req, res) => { + const { email, otp } = req.body; + const pendingUser = pendingUsers.get(email); + if (!pendingUser) { + return sendError(res, 'No pending registration found', 404); } - const user = await userModel.findById(userId); - if (!user) { - return sendError(res, 'User not found', 404); - } + // Verify OTP + const isOtpValid = await verifyOTP(otp, pendingUser.verifyOtp); + if (!isOtpValid) { + return sendError(res, 'Invalid OTP', 400); + } - const isOtpValid = await verifyOTP(otp, user.verifyOtp); - if (!isOtpValid) { - return sendError(res, 'Invalid OTP', 400); - } + // Check if OTP expired + const user = new userModel({ + name: pendingUser.name, + email: pendingUser.email, + password: pendingUser.password, + isAccountVerified: true + }); + await user.save(); + pendingUsers.delete(email) + - user.isAccountVerified = true; - user.verifyOtp = ''; - user.verifyOtpExpireAt = 0; - await user.save(); - sendSuccess(res, {}, 'Email verified successfully'); + const welcomeMailOptions = { + from: process.env.SENDER_EMAIL, + to: user.email, + subject: 'Welcome to PlantZ', + text: `Welcome to PlantZ website. Your account has been created with email id: ${user.email}`, + }; + + try { + await transporter.sendMail(welcomeMailOptions); + } catch (error) { + console.error('Error sending welcome email:', error); + } + clearAuthCookie(res); + const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '7d' }); + setAuthCookie(res, token); + sendSuccess(res, { + user: { + _id: user._id, + name: user.name, + email: user.email, + isAccountVerified: user.isAccountVerified + } + }, 'Email verified and account created successfully'); }), ]; + // Check if user is authenticated export const isAuthenticated = [ protect, @@ -269,4 +282,4 @@ export const resetPassword = asyncHandler(async (req, res) => { await user.save(); sendSuccess(res, {}, 'Password has been reset successfully'); -}); \ No newline at end of file +}); diff --git a/backend/routes/authRoutes.js b/backend/routes/authRoutes.js index 5ef85b9..0dec801 100644 --- a/backend/routes/authRoutes.js +++ b/backend/routes/authRoutes.js @@ -22,7 +22,7 @@ authRouter.post('/reset-password', resetPassword); // Authenticated routes authRouter.post('/logout', userAuth, logout); authRouter.get('/send-verify-otp', userAuth, sendVerifyOtp); -authRouter.post('/verify-account', userAuth, verifyEmail); +authRouter.post('/verify-account', verifyEmail); authRouter.get('/is-auth', userAuth, isAuthenticated); -export default authRouter; \ No newline at end of file +export default authRouter; diff --git a/frontend/src/context/AppContext.jsx b/frontend/src/context/AppContext.jsx index 1435478..83b8f7b 100644 --- a/frontend/src/context/AppContext.jsx +++ b/frontend/src/context/AppContext.jsx @@ -18,6 +18,7 @@ export const AppContextProvider = (props) => { const [isLoggedIn, setIsLoggedIn] = useState(false) const [userData, setUserData] = useState(false) const [plants, setPlants] = useState(null) + const [userEmail, setUserEmail] = useState(''); // State to hold user email const getAuthState = async () => { try { @@ -71,7 +72,8 @@ useEffect(()=>{ isLoggedIn, setIsLoggedIn, userData, setUserData, getUserData, - plants, setPlants + plants, setPlants, + userEmail, setUserEmail } @@ -80,4 +82,4 @@ useEffect(()=>{ {props.children} ) -} \ No newline at end of file +} diff --git a/frontend/src/pages/EmailVerify.jsx b/frontend/src/pages/EmailVerify.jsx index c1f5c54..34e3470 100644 --- a/frontend/src/pages/EmailVerify.jsx +++ b/frontend/src/pages/EmailVerify.jsx @@ -33,14 +33,15 @@ const EmailVerify = () => { } }); }; - + const { userEmail } = useContext(AppContent); + console.log(userEmail); const onSubmitHandler = async (e) => { try { e.preventDefault(); const otpArray = inputRefs.current.map((e) => e.value); const otp = otpArray.join(''); - const { data } = await axios.post(backendUrl + '/api/auth/verify-account', { otp }); + const { data } = await axios.post(backendUrl + '/api/auth/verify-account', { email: userEmail,otp }); if (data.success) { toast.success(data.message); getUserData(); @@ -84,4 +85,4 @@ const EmailVerify = () => { ); }; -export default EmailVerify; \ No newline at end of file +export default EmailVerify; diff --git a/frontend/src/pages/Login.jsx b/frontend/src/pages/Login.jsx index 0063ced..c90b4b1 100644 --- a/frontend/src/pages/Login.jsx +++ b/frontend/src/pages/Login.jsx @@ -9,13 +9,13 @@ import { FiEyeOff, FiEye } from "react-icons/fi"; const Login = () => { const navigate = useNavigate(); - const { backendUrl, setIsLoggedIn, getUserData } = useContext(AppContent); + const { backendUrl, setIsLoggedIn, getUserData, setUserEmail } = useContext(AppContent); const [state, setState] = useState('Login'); const [name, setName] = useState(''); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [showPassword, setShowPassword] = useState(false); - + const onSubmitHandler = async (e) => { e.preventDefault(); @@ -35,8 +35,8 @@ const Login = () => { }); if (data.success) { + setUserEmail(email); setIsLoggedIn(true); - getUserData(); navigate('/email-verify'); toast.success(data.message || 'Registration successful!'); } @@ -189,4 +189,4 @@ const Login = () => { ); }; -export default Login; \ No newline at end of file +export default Login; diff --git a/frontend/src/pages/ProfileSettingsPage.jsx b/frontend/src/pages/ProfileSettingsPage.jsx index b72fe5e..602b924 100644 --- a/frontend/src/pages/ProfileSettingsPage.jsx +++ b/frontend/src/pages/ProfileSettingsPage.jsx @@ -570,7 +570,7 @@ const ProfileSettingsPage = () => {

Danger Zone

@@ -640,4 +640,4 @@ const ProfileSettingsPage = () => { ); }; -export default ProfileSettingsPage; \ No newline at end of file +export default ProfileSettingsPage;