diff --git a/.env.sample b/.env.sample
index 2d62b532..f46b3e57 100644
--- a/.env.sample
+++ b/.env.sample
@@ -2,6 +2,7 @@ MONGO_URL=mongodb://localhost:27017
PORT=8080
REFRESH_TOKEN_COOKIE_EXPIRE=30
REFRESH_TOKEN_SECRET=XYZ
+
GOOGLE_CLIENT_ID=your_client_id
GOOGLE_CLIENT_SECRET=your_client_secret
JWT_SECRET=yourSecretKey
diff --git a/client/src/App.js b/client/src/App.js
index f4c79b13..a12b8655 100644
--- a/client/src/App.js
+++ b/client/src/App.js
@@ -33,6 +33,7 @@ import CustomerProfile from './Pages/CustomerProfile.jsx';
import GiftCards from './Pages/GiftCards.jsx';
import Careers from './Pages/Careers.jsx';
import NotFound from './Pages/NotFound.jsx';
+import ResetPassword from "./Pages/ResetPassword.jsx";
function App() {
const [darkMode, setDarkMode] = useState(false);
@@ -79,6 +80,7 @@ function App() {
} />
} />
} />
+ } />
} /> {/* Fallback route */}
diff --git a/client/src/Components/index.js b/client/src/Components/index.js
deleted file mode 100644
index 2820e9f1..00000000
--- a/client/src/Components/index.js
+++ /dev/null
@@ -1,11 +0,0 @@
-
-import Profile from "./CustomerProfile/Profile.jsx";
-import Product from "./Product.jsx"
-import Footer from "./Footer/Footer.jsx"
-import Navbar from "./NavBar/NavBar.jsx"
-export {
- Profile,
- Product,
- Footer,
- Navbar
-}
\ No newline at end of file
diff --git a/client/src/Pages/Home.jsx b/client/src/Pages/Home.jsx
index 85af771f..f1aa4968 100644
--- a/client/src/Pages/Home.jsx
+++ b/client/src/Pages/Home.jsx
@@ -9,7 +9,7 @@ import Newarrivals from "./Newarrivals";
import Review from "./Review";
import Trending from "../Components/Trending";
import Book from "../Components/Card/Book";
-import Review from './Review';
+//import Review from './Review';
const Home = () => {
const [isLoading, setIsLoading] = useState(true);
diff --git a/client/src/Pages/LoginPage.jsx b/client/src/Pages/LoginPage.jsx
index 454f3aae..a0880325 100644
--- a/client/src/Pages/LoginPage.jsx
+++ b/client/src/Pages/LoginPage.jsx
@@ -137,11 +137,21 @@ const LoginPage = () => {
{/* Google Login Button */}
-
-
- Don't have an account?{' '} Sign up
-
-
+
+ {/* Sign up link */}
+
+ Don't have an account?{' '} Sign up
+
+
+ {/* Add spacing between the two sections */}
+
{/* This adds vertical spacing */}
+
+ {/* Forgot password link */}
+
+ Forgot Password?{' '} Reset here {/* Update link if necessary */}
+
+
+
diff --git a/client/src/Pages/ResetPassword.jsx b/client/src/Pages/ResetPassword.jsx
new file mode 100644
index 00000000..432855b6
--- /dev/null
+++ b/client/src/Pages/ResetPassword.jsx
@@ -0,0 +1,179 @@
+import React, { useState } from "react";
+import TextField from "@mui/material/TextField";
+import Button from "@mui/material/Button";
+import IconButton from "@mui/material/IconButton";
+import VisibilityIcon from "@mui/icons-material/Visibility";
+import VisibilityOffIcon from "@mui/icons-material/VisibilityOff";
+import { Box, Container, Grid, Typography } from "@mui/material";
+import Lottie from "lottie-react";
+import loginAnimation from "../Lottie-animation/loginAnimation.json"; // Ensure the animation is correct for this page
+import axios from "axios";
+import toast, { Toaster } from "react-hot-toast";
+import { Link, useNavigate } from "react-router-dom";
+
+const ResetPassword = () => {
+ const [email, setEmail] = useState("");
+ const [password, setPassword] = useState("");
+ const [confirmPassword, setConfirmPassword] = useState(""); // Added state for confirm password
+ const [showPassword, setShowPassword] = useState(false); // State for toggling password visibility
+ const [error, setError] = useState("");
+ let navigate = useNavigate();
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+
+ // Reset error state
+ setError("");
+
+ // Validate that password and confirmPassword match
+ if (password !== confirmPassword) {
+ setError("Re-enter password does not match with new password!");
+ return;
+ }
+
+ try {
+ const response = await axios.post("http://localhost:8080/customer/resetpassword", {
+ email,
+ newPassword: password, // Send new password
+ });
+ toast.success("Password reset successfully!");
+ navigate("/login", { replace: true });
+ } catch (err) {
+ // Handle different error responses
+ if (err.response && err.response.data && err.response.data.error) {
+ setError(err.response.data.error);
+ } else {
+ setError("An unexpected error occurred.");
+ }
+ }
+ };
+
+ // Function to toggle password visibility
+ const togglePasswordVisibility = () => {
+ setShowPassword(!showPassword);
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+ {/* Add a Box with hover effect */}
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default ResetPassword;
diff --git a/controllers/customerController.js b/controllers/customerController.js
index cde40bdc..6563432d 100644
--- a/controllers/customerController.js
+++ b/controllers/customerController.js
@@ -6,6 +6,8 @@ const errorHandler = require("../utils/errorHandler");
const responseHandler = require("../utils/responseHandler");
const jwt = require("jsonwebtoken");
require("dotenv").config();
+const bcrypt = require("bcryptjs");
+const saltRounds = 10;
const validator = require("validator");
const disposableEmailDomains = require("disposable-email-domains");
@@ -204,6 +206,8 @@ exports.getCustomerDetails = catchAsyncErrors(async (req, res, next) => {
});
});
+
+
// UPDATE CUSTOMER PASSWORD
exports.updatePassword = catchAsyncErrors(async (req, res, next) => {
const customer = await Customer.findById(req.user.id).select("+password");
@@ -213,17 +217,11 @@ exports.updatePassword = catchAsyncErrors(async (req, res, next) => {
);
if (!isPasswordMatched) {
- return res
- .status(404)
- .send(
- errorHandler(404, "Bad Request", "Please enter the correct password")
- );
+ return next(new ErrorHandler("Old password is incorrect", 400));
}
if (req.body.newPassword !== req.body.confirmPassword) {
- return res
- .status(404)
- .send(errorHandler(404, "Bad Request", "Password do not match"));
+ return next(new ErrorHandler("Password does not match", 400));
}
customer.password = req.body.newPassword;
@@ -233,6 +231,8 @@ exports.updatePassword = catchAsyncErrors(async (req, res, next) => {
sendToken(customer, 200, res);
});
+
+
// UPDATE CUSTOMER PROFILE
exports.updateProfile = catchAsyncErrors(async (req, res, next) => {
const newCustomerData = {
@@ -261,6 +261,35 @@ exports.updateProfile = catchAsyncErrors(async (req, res, next) => {
});
});
+//RESET Password
+exports.resetPassword = async (req, res) => {
+ const { email, newPassword } = req.body; // expecting newPassword
+
+ if (!newPassword) {
+ return res.status(400).json({ error: 'New password is required.' });
+ }
+
+ try {
+ const hashedPassword = await bcrypt.hash(newPassword, saltRounds); // Hash new password
+
+ const updatedUser = await Customer.findOneAndUpdate(
+ { email }, // Find user by email
+ { $set: { password: hashedPassword } }, // Set new hashed password
+ { new: true }
+ );
+
+ if (updatedUser) {
+ return res.json({ message: 'Password updated successfully.' });
+ } else {
+ return res.status(404).json({ error: 'User not found.' });
+ }
+ } catch (error) {
+ console.error('Error updating password:', error.message);
+ res.status(500).json({ error: 'Internal Server Error' });
+ }
+};
+
+
exports.addFeedback = catchAsyncErrors(async (req, res, next) => {
const { feedback, topic } = req.body;
const newFeedback = await Feedback.create({
diff --git a/index.js b/index.js
index 9355b814..9d52231c 100644
--- a/index.js
+++ b/index.js
@@ -181,4 +181,4 @@ function closeModal() {
function purchaseBook() {
alert('Book purchased!');
closeModal();
-}
\ No newline at end of file
+}
diff --git a/package-lock.json b/package-lock.json
index 70beb7af..b5771433 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2330,6 +2330,31 @@
"node": ">= 0.8"
}
},
+ "node_modules/react": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
+ "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
+ "peer": true,
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
+ "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
+ "peer": true,
+ "dependencies": {
+ "loose-envify": "^1.1.0",
+ "scheduler": "^0.23.2"
+ },
+ "peerDependencies": {
+ "react": "^18.3.1"
+ }
+ },
"node_modules/react-is": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
@@ -2444,6 +2469,15 @@
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
+ "node_modules/scheduler": {
+ "version": "0.23.2",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
+ "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
+ "peer": true,
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ }
+ },
"node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
diff --git a/routes/customerRoutes.js b/routes/customerRoutes.js
index 4bd14b4f..2ee19fc1 100644
--- a/routes/customerRoutes.js
+++ b/routes/customerRoutes.js
@@ -6,9 +6,8 @@ const {
updatePassword,
updateProfile,
logoutCustomer,
- addFeedback
-
-
+ addFeedback,
+ resetPassword
} = require("../controllers/customerController.js");
const {
addTocart,
@@ -32,8 +31,7 @@ router.route("/password/update").put(isAuthenticatedUser, updatePassword);
router.route("/me/update").put(isAuthenticatedUser, updateProfile);
-
-
+router.route("/resetpassword").post(resetPassword);
//cart routes
@@ -56,4 +54,4 @@ router.route("/cart").get(isAuthenticatedUser,getCartItems);
//giving feedback
router.route("/add-feedback").post(isAuthenticatedUser,addFeedback);
-module.exports = router;
\ No newline at end of file
+module.exports = router;