{
- setPasswd(e.target.value);
- }}
- required
- />
-
-
{
- setPpic(e.target.value);
- }}
- />
-
-
-
{
- setStreet(e.target.value);
- }}
- required
- />
-
-
-
{
- setCity(e.target.value);
- }}
- />
-
-
-
{
- setState(e.target.value);
- }}
- />
-
-
-
{
- setPincode(e.target.value);
- }}
- />
-
+
+
{
+ setPincode(parseInt(e.target.value));
+ }}
+ required
+ />
+
+
+
-
+
+ )}
-
-
-
-
-
-
-
-
-
-
- HAVE A ACCOUNT ?!
-
-
- Login
-
-
-
+
+
+ Already Registered?
+
+
diff --git a/client/src/pages/Verify-email/index.jsx b/client/src/pages/Verify-email/index.jsx
new file mode 100644
index 0000000..397fc01
--- /dev/null
+++ b/client/src/pages/Verify-email/index.jsx
@@ -0,0 +1,68 @@
+import React, { useEffect, useState } from 'react';
+import { useLocation, useNavigate } from 'react-router-dom';
+import axios from 'axios';
+import toast from 'react-hot-toast';
+
+const VerifyEmail = () => {
+ const location = useLocation();
+ const navigate = useNavigate();
+ const query = new URLSearchParams(location.search);
+ const token = query.get('token');
+ const email = query.get('email');
+ const status = query.get('status');
+ const [isVerified, setIsVerified] = useState(false);
+
+ useEffect(() => {
+ const verifyAccount = async () => {
+ if (status === 'success') {
+ toast.success('Account verified successfully!');
+ setIsVerified(true);
+ return;
+ }
+
+ if (token && email && !isVerified) {
+ try {
+ const response = await axios.get(`http://localhost:3000/api/users/verify-email?token=${token}&email=${email}`);
+ if (response.data.success) {
+ toast.success('Account verified successfully!');
+ setIsVerified(true);
+
+ } else {
+ toast.error('Verification failed. Please try again.');
+ }
+ } catch (error) {
+ toast.error('Verification failed. Please try again.');
+ }
+ }
+ };
+
+ verifyAccount();
+ }, [token, email, status, isVerified]);
+
+ const handleLoginRedirect = () => {
+ navigate('/login');
+ };
+
+ return (
+
+
+ {isVerified ? (
+
+
Verification Successful
+
Your account has been verified successfully!
+
+
+
+ ) : (
+
+
Verification failed
+
Try after some time.
+
+ )}
+
+
+ );
+};
+
+export default VerifyEmail;
diff --git a/server/controllers/user.js b/server/controllers/user.js
index c66cd42..8d2d74b 100644
--- a/server/controllers/user.js
+++ b/server/controllers/user.js
@@ -1,6 +1,8 @@
import bcrypt from "bcryptjs";
import { sendCookie } from "../utils/features.js";
import { PrismaClient } from "@prisma/client";
+import { sendVerifyEmail } from "../utils/verify-email.js";
+import { v4 as uuidv4 } from "uuid";
const prisma = new PrismaClient();
@@ -18,22 +20,42 @@ const signup = async (req, res) => {
message: "User already exists."
});
}
-
- const hpasswd = await bcrypt.hash(passwd, 10);
- const newUser = await prisma.mainuser.create({
- data: {
+
+ const token = uuidv4();
+ const hashedToken = await bcrypt.hash(token, 10);
+ const hashedPassword = await bcrypt.hash(passwd, 10);
+
+
+ await prisma.tempUser.upsert({
+ where: { email },
+ update: {
+ name,
+ profilepic:ppic,
+ passwd: hashedPassword,
+ street,
+ city,
+ state,
+ pincode: parseInt(pincode),
+ token: hashedToken,
+ },
+ create: {
name,
email,
- profilepic: ppic,
- passwd: hpasswd,
+ profilepic:ppic,
+ passwd: hashedPassword,
street,
city,
state,
- pincode: parseInt(pincode), // making pincode as an integer because it's get a string from 'req'
+ pincode: parseInt(pincode),
+ token: hashedToken,
},
});
- sendCookie(newUser.email, res, "Registered Successfully", 201);
+
+ const verificationLink = `http://localhost:5173/verify-email?token=${token}&email=${email}`;
+ await sendVerifyEmail(email, verificationLink);
+ res.status(200).json({ message: 'Verification email sent' });
+
} catch (err) {
console.error(err);
res.status(500).json({
diff --git a/server/controllers/verifyEmail.js b/server/controllers/verifyEmail.js
new file mode 100644
index 0000000..bd160e2
--- /dev/null
+++ b/server/controllers/verifyEmail.js
@@ -0,0 +1,51 @@
+
+import { PrismaClient } from '@prisma/client';
+import bcrypt from 'bcryptjs';
+
+
+const prisma = new PrismaClient();
+
+export const verifyEmail = async (req, res) => {
+ const { token, email } = req.query;
+
+ try {
+
+ const tempUser = await prisma.tempUser.findUnique({
+ where: { email },
+ });
+
+ if (!tempUser) {
+ return res.status(400).json({ message: 'Invalid or expired token' });
+ }
+
+ const isValid = await bcrypt.compare(token, tempUser.token);
+
+ if (!isValid) {
+ return res.status(400).json({ message: 'Invalid or expired token' });
+ }
+
+ await prisma.mainuser.create({
+ data: {
+ name: tempUser.name,
+ email: tempUser.email,
+ profilepic: tempUser.profilepic,
+ passwd: tempUser.passwd,
+ street: tempUser.street,
+ city: tempUser.city,
+ state: tempUser.state,
+ pincode: tempUser.pincode,
+ },
+ });
+
+ await prisma.tempUser.delete({
+ where: { email },
+ });
+
+ res.status(200).json({ success: true, message: 'Account verified successfully!' });
+
+ } catch (error) {
+ console.error('Error verifying email:', error);
+ res.status(500).json({ message: 'Internal Server Error' });
+ }
+};
+
diff --git a/server/prisma/migrations/20240805211932_add_temp_user_model/migration.sql b/server/prisma/migrations/20240805211932_add_temp_user_model/migration.sql
new file mode 100644
index 0000000..46dd3f8
--- /dev/null
+++ b/server/prisma/migrations/20240805211932_add_temp_user_model/migration.sql
@@ -0,0 +1,17 @@
+-- CreateTable
+CREATE TABLE `TempUser` (
+ `id` INTEGER NOT NULL AUTO_INCREMENT,
+ `name` VARCHAR(191) NOT NULL,
+ `email` VARCHAR(191) NOT NULL,
+ `profilepic` VARCHAR(191) NULL,
+ `passwd` VARCHAR(191) NOT NULL,
+ `street` VARCHAR(191) NOT NULL,
+ `city` VARCHAR(191) NOT NULL,
+ `state` VARCHAR(191) NOT NULL,
+ `pincode` INTEGER NOT NULL,
+ `token` VARCHAR(191) NOT NULL,
+ `createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
+
+ UNIQUE INDEX `TempUser_email_key`(`email`),
+ PRIMARY KEY (`id`)
+) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
diff --git a/server/prisma/schema.prisma b/server/prisma/schema.prisma
index 61a8c2b..a6c1a7f 100644
--- a/server/prisma/schema.prisma
+++ b/server/prisma/schema.prisma
@@ -41,6 +41,20 @@ model Designer {
mainuser Mainuser @relation(fields: [email], references: [email])
}
+model TempUser {
+ id Int @id @default(autoincrement())
+ name String
+ email String @unique
+ profilepic String?
+ passwd String
+ street String
+ city String
+ state String
+ pincode Int
+ token String
+ createdAt DateTime @default(now())
+}
+
model Mainuser {
name String
email String @id
diff --git a/server/routes/user.js b/server/routes/user.js
index 1585f47..16635c6 100644
--- a/server/routes/user.js
+++ b/server/routes/user.js
@@ -2,7 +2,7 @@ import express from "express";
import { login, signup, getMyProfile,updateUserProfile, registerdesigner, registerretailer } from "../controllers/user.js";
import { requestPasswordReset, resetPassword } from "../controllers/forgotPassword.js";
import { isAuthenticated } from "../middlewares/auth.js";
-
+import { verifyEmail } from "../controllers/verifyEmail.js";
const router = express.Router();
@@ -10,6 +10,8 @@ router.post("/login", login);
router.post("/signup", signup);
+router.get('/verify-email', verifyEmail);
+
router.post("/forgot-password", requestPasswordReset);
router.post("/reset-password/:token/:id", resetPassword);
diff --git a/server/utils/verify-email.js b/server/utils/verify-email.js
new file mode 100644
index 0000000..e40e18b
--- /dev/null
+++ b/server/utils/verify-email.js
@@ -0,0 +1,28 @@
+import nodemailer from "nodemailer";
+
+export const sendVerifyEmail = async (email, verificationLink) => {
+ const transporter = nodemailer.createTransport({
+ service: "Gmail",
+ port: 465,
+
+ secureConnection:false,
+
+ auth: {
+ user: process.env.EMAIL,
+ pass: process.env.PASSWORD,
+ },
+
+ tls: {
+ rejectunAuthorized:true
+ }
+ });
+
+ const mailOptions = {
+ from: process.env.EMAIL,
+ to: email,
+ subject: 'Email Verification',
+ text:`Click the following link to verify your email: ${verificationLink}`,
+ };
+
+ await transporter.sendMail(mailOptions);
+};