From 8f29c9303dcf3f8504a0aa40a18a5f1902e5453b Mon Sep 17 00:00:00 2001 From: Raza Date: Fri, 4 Oct 2024 16:26:32 +0530 Subject: [PATCH] added --- client/package-lock.json | 13 ++ client/package.json | 1 + client/src/App.js | 2 + client/src/Pages/LoginPage.jsx | 10 +- client/src/Pages/ResetPassword.jsx | 111 ++++++++++++ .env.sample => server/.env.sample | 0 .gitignore => server/.gitignore | 0 .../CODE_OF_CONDUCT.md | 0 CONTRIBUTING.md => server/CONTRIBUTING.md | 0 Dockerfile => server/Dockerfile | 0 LICENSE => server/LICENSE | 0 .../controllers}/adminController.js | 0 .../controllers}/cartController.js | 0 .../controllers}/customerController.js | 35 +++- .../controllers}/orderController.js | 0 .../controllers}/productController.js | 0 index.js => server/index.js | 12 +- {middlewares => server/middlewares}/auth.js | 0 .../middlewares}/catchAsyncErrors.js | 0 {middlewares => server/middlewares}/error.js | 0 {models => server/models}/cartSchema.js | 0 {models => server/models}/customerSchema.js | 9 +- {models => server/models}/feebackSchema.js | 0 {models => server/models}/orderSchema.js | 0 {models => server/models}/productSchema.js | 0 {models => server/models}/wishlistSchema.js | 32 ++-- package-lock.json => server/package-lock.json | 0 package.json => server/package.json | 0 {routes => server/routes}/adminRoutes.js | 0 {routes => server/routes}/cartRoutes.js | 0 {routes => server/routes}/customerRoutes.js | 10 +- {routes => server/routes}/orderRoutes.js | 0 {routes => server/routes}/productRoutes.js | 0 {routes => server/routes}/wishlistRoutes.js | 166 +++++++++--------- {utils => server/utils}/errorHandler.js | 0 {utils => server/utils}/jwtToken.js | 0 36 files changed, 279 insertions(+), 122 deletions(-) create mode 100644 client/src/Pages/ResetPassword.jsx rename .env.sample => server/.env.sample (100%) rename .gitignore => server/.gitignore (100%) rename CODE_OF_CONDUCT.md => server/CODE_OF_CONDUCT.md (100%) rename CONTRIBUTING.md => server/CONTRIBUTING.md (100%) rename Dockerfile => server/Dockerfile (100%) rename LICENSE => server/LICENSE (100%) rename {controllers => server/controllers}/adminController.js (100%) rename {controllers => server/controllers}/cartController.js (100%) rename {controllers => server/controllers}/customerController.js (89%) rename {controllers => server/controllers}/orderController.js (100%) rename {controllers => server/controllers}/productController.js (100%) rename index.js => server/index.js (90%) rename {middlewares => server/middlewares}/auth.js (100%) rename {middlewares => server/middlewares}/catchAsyncErrors.js (100%) rename {middlewares => server/middlewares}/error.js (100%) rename {models => server/models}/cartSchema.js (100%) rename {models => server/models}/customerSchema.js (88%) rename {models => server/models}/feebackSchema.js (100%) rename {models => server/models}/orderSchema.js (100%) rename {models => server/models}/productSchema.js (100%) rename {models => server/models}/wishlistSchema.js (95%) rename package-lock.json => server/package-lock.json (100%) rename package.json => server/package.json (100%) rename {routes => server/routes}/adminRoutes.js (100%) rename {routes => server/routes}/cartRoutes.js (100%) rename {routes => server/routes}/customerRoutes.js (92%) rename {routes => server/routes}/orderRoutes.js (100%) rename {routes => server/routes}/productRoutes.js (100%) rename {routes => server/routes}/wishlistRoutes.js (96%) rename {utils => server/utils}/errorHandler.js (100%) rename {utils => server/utils}/jwtToken.js (100%) diff --git a/client/package-lock.json b/client/package-lock.json index 7330ba98..5bb619e7 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -24,6 +24,7 @@ "react-icons": "^5.2.1", "react-router-dom": "^6.23.1", "react-scripts": "^5.0.1", + "react-toastify": "^10.0.5", "styled-components": "^6.1.12", "swiper": "^11.1.4", "tailwindcss": "^3.4.4", @@ -15966,6 +15967,18 @@ } } }, + "node_modules/react-toastify": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.5.tgz", + "integrity": "sha512-mNKt2jBXJg4O7pSdbNUfDdTsK9FIdikfsIE/yUCxbAEXl4HMyJaivrVFcn3Elvt5xvCQYhUZm+hqTIu1UXM3Pw==", + "dependencies": { + "clsx": "^2.1.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", diff --git a/client/package.json b/client/package.json index 215e19ab..cd041ebb 100644 --- a/client/package.json +++ b/client/package.json @@ -19,6 +19,7 @@ "react-icons": "^5.2.1", "react-router-dom": "^6.23.1", "react-scripts": "^5.0.1", + "react-toastify": "^10.0.5", "styled-components": "^6.1.12", "swiper": "^11.1.4", "tailwindcss": "^3.4.4", diff --git a/client/src/App.js b/client/src/App.js index c0693d5e..40bb091b 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -22,6 +22,7 @@ import Preloader from "./Components/Preloader.jsx"; import { Toast } from "./Toast/Toast.js"; import GoToTop from "./Components/GoToTop.jsx"; import License from "./Pages/Licensing.jsx"; +import ResetPassword from "./Pages/ResetPassword.jsx"; function App() { const [darkMode, setDarkMode] = useState(false); @@ -58,6 +59,7 @@ function App() { } /> } /> } /> + } /> } /> {/* Fallback route */} diff --git a/client/src/Pages/LoginPage.jsx b/client/src/Pages/LoginPage.jsx index ee3e9d79..b8e80fd0 100644 --- a/client/src/Pages/LoginPage.jsx +++ b/client/src/Pages/LoginPage.jsx @@ -126,9 +126,13 @@ const LoginPage = () => { > Login - - Don't have an account? Sign up - + + Don't have an account? Sign up + + + Forgot your password? Reset Password + + diff --git a/client/src/Pages/ResetPassword.jsx b/client/src/Pages/ResetPassword.jsx new file mode 100644 index 00000000..2d2e2d6e --- /dev/null +++ b/client/src/Pages/ResetPassword.jsx @@ -0,0 +1,111 @@ +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 [showPassword, setShowPassword] = useState(false); // State for toggling password visibility + const [error, setError] = useState(""); + let navigate = useNavigate(); + + const handleSubmit = async (e) => { + e.preventDefault(); + + 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) { + setError(err.response.data.error); // Fix the error field + } + }; + + // Function to toggle password visibility + const togglePasswordVisibility = () => { + setShowPassword(!showPassword); + }; + + return ( + <> + + +
+ + + + + + + {/* Set maxWidth to 600px */} +
+ + Reset Password + + setEmail(e.target.value)} + margin="normal" + fullWidth // Use fullWidth for consistent sizing + /> + + setPassword(e.target.value)} + margin="normal" + fullWidth // Use fullWidth for consistent sizing + /> + + {showPassword ? : } + + + {error && ( + + {error} + + )} + + + Go to Login + + +
+
+
+
+ + ); +}; + +export default ResetPassword; diff --git a/.env.sample b/server/.env.sample similarity index 100% rename from .env.sample rename to server/.env.sample diff --git a/.gitignore b/server/.gitignore similarity index 100% rename from .gitignore rename to server/.gitignore diff --git a/CODE_OF_CONDUCT.md b/server/CODE_OF_CONDUCT.md similarity index 100% rename from CODE_OF_CONDUCT.md rename to server/CODE_OF_CONDUCT.md diff --git a/CONTRIBUTING.md b/server/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING.md rename to server/CONTRIBUTING.md diff --git a/Dockerfile b/server/Dockerfile similarity index 100% rename from Dockerfile rename to server/Dockerfile diff --git a/LICENSE b/server/LICENSE similarity index 100% rename from LICENSE rename to server/LICENSE diff --git a/controllers/adminController.js b/server/controllers/adminController.js similarity index 100% rename from controllers/adminController.js rename to server/controllers/adminController.js diff --git a/controllers/cartController.js b/server/controllers/cartController.js similarity index 100% rename from controllers/cartController.js rename to server/controllers/cartController.js diff --git a/controllers/customerController.js b/server/controllers/customerController.js similarity index 89% rename from controllers/customerController.js rename to server/controllers/customerController.js index b3052ad6..f2f3b5b9 100644 --- a/controllers/customerController.js +++ b/server/controllers/customerController.js @@ -5,6 +5,8 @@ const sendToken = require("../utils/jwtToken"); const ErrorHandler = require("../utils/errorHandler.js"); const jwt = require("jsonwebtoken"); require("dotenv").config(); +const bcrypt = require("bcryptjs"); +const saltRounds = 10; // CUSTOMER REGISTRATION ROUTE const validator = require('validator'); const disposableEmailDomains = require('disposable-email-domains'); @@ -204,6 +206,37 @@ 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; @@ -282,4 +315,4 @@ exports.exchangeToken = catchAsyncErrors(async (req, res, next) => { } catch (error) { return next(new ErrorHandler("Invalid refresh token", 401)); } -}); \ No newline at end of file +}); diff --git a/controllers/orderController.js b/server/controllers/orderController.js similarity index 100% rename from controllers/orderController.js rename to server/controllers/orderController.js diff --git a/controllers/productController.js b/server/controllers/productController.js similarity index 100% rename from controllers/productController.js rename to server/controllers/productController.js diff --git a/index.js b/server/index.js similarity index 90% rename from index.js rename to server/index.js index 61169667..5924d6b3 100644 --- a/index.js +++ b/server/index.js @@ -21,18 +21,14 @@ const MONGO_URL = process.env.MONGO_URL; const cors = require("cors"); app.use( cors({ - origin: "http://localhost:3000", // your frontend's origin - optionsSuccessStatus: 200, - - origin: "http://localhost:3000", // Allow requests from localhost:3000 - credentials: true, // Allow sending cookies from the frontend - methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], // Allow the HTTP methods you use - allowedHeaders: ["Content-Type", "auth-token", "Origin", "X-Requested-With", "Accept"], // Allow headers - + credentials: true, // Allow cookies + methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], // Allow these methods + allowedHeaders: ["Content-Type", "auth-token", "Origin", "X-Requested-With", "Accept"], // Allow these headers }) ); + // Check if MONGO_URL is defined if (!MONGO_URL) { console.error("MONGO_URL is not defined in the environment variables."); diff --git a/middlewares/auth.js b/server/middlewares/auth.js similarity index 100% rename from middlewares/auth.js rename to server/middlewares/auth.js diff --git a/middlewares/catchAsyncErrors.js b/server/middlewares/catchAsyncErrors.js similarity index 100% rename from middlewares/catchAsyncErrors.js rename to server/middlewares/catchAsyncErrors.js diff --git a/middlewares/error.js b/server/middlewares/error.js similarity index 100% rename from middlewares/error.js rename to server/middlewares/error.js diff --git a/models/cartSchema.js b/server/models/cartSchema.js similarity index 100% rename from models/cartSchema.js rename to server/models/cartSchema.js diff --git a/models/customerSchema.js b/server/models/customerSchema.js similarity index 88% rename from models/customerSchema.js rename to server/models/customerSchema.js index 303fb5ef..25d69610 100644 --- a/models/customerSchema.js +++ b/server/models/customerSchema.js @@ -2,7 +2,7 @@ const mongoose = require("mongoose"); const validator = require("validator"); const bcrypt = require("bcryptjs"); const jwt = require("jsonwebtoken"); -const dotenv = require(`dotenv`); +const dotenv = require("dotenv"); dotenv.config({ path: `.env` }); const customerSchema = new mongoose.Schema({ @@ -38,8 +38,8 @@ const customerSchema = new mongoose.Schema({ type: String, default: "user", }, - refreshTOken:{ - type:String, + refreshToken: { // Corrected key name + type: String, required: false, }, createdAt: { @@ -61,11 +61,10 @@ customerSchema.pre("save", async function (next) { // JWT TOKEN customerSchema.methods.getJWTToken = function () { - return jwt.sign({ id: this._id }, process.env.JWT_SECRET); + return jwt.sign({ id: this._id }, process.env.JWT_SECRET, { expiresIn: '1h' }); // Consider adding expiration }; // Compare Password - customerSchema.methods.comparePassword = async function (password) { return await bcrypt.compare(password, this.password); }; diff --git a/models/feebackSchema.js b/server/models/feebackSchema.js similarity index 100% rename from models/feebackSchema.js rename to server/models/feebackSchema.js diff --git a/models/orderSchema.js b/server/models/orderSchema.js similarity index 100% rename from models/orderSchema.js rename to server/models/orderSchema.js diff --git a/models/productSchema.js b/server/models/productSchema.js similarity index 100% rename from models/productSchema.js rename to server/models/productSchema.js diff --git a/models/wishlistSchema.js b/server/models/wishlistSchema.js similarity index 95% rename from models/wishlistSchema.js rename to server/models/wishlistSchema.js index bded4195..a5099916 100644 --- a/models/wishlistSchema.js +++ b/server/models/wishlistSchema.js @@ -1,16 +1,16 @@ -const mongoose = require("mongoose"); - -const wishlistSchema = mongoose.Schema({ - user: { - type: mongoose.Schema.ObjectId, - ref: "Customer", - required: true, - }, - product: { - type: mongoose.Schema.ObjectId, - ref: "Product", - required: true, - }, -}); - -module.exports = mongoose.model("Wishlist", wishlistSchema); +const mongoose = require("mongoose"); + +const wishlistSchema = mongoose.Schema({ + user: { + type: mongoose.Schema.ObjectId, + ref: "Customer", + required: true, + }, + product: { + type: mongoose.Schema.ObjectId, + ref: "Product", + required: true, + }, +}); + +module.exports = mongoose.model("Wishlist", wishlistSchema); diff --git a/package-lock.json b/server/package-lock.json similarity index 100% rename from package-lock.json rename to server/package-lock.json diff --git a/package.json b/server/package.json similarity index 100% rename from package.json rename to server/package.json diff --git a/routes/adminRoutes.js b/server/routes/adminRoutes.js similarity index 100% rename from routes/adminRoutes.js rename to server/routes/adminRoutes.js diff --git a/routes/cartRoutes.js b/server/routes/cartRoutes.js similarity index 100% rename from routes/cartRoutes.js rename to server/routes/cartRoutes.js diff --git a/routes/customerRoutes.js b/server/routes/customerRoutes.js similarity index 92% rename from routes/customerRoutes.js rename to server/routes/customerRoutes.js index 4bd14b4f..2ee19fc1 100644 --- a/routes/customerRoutes.js +++ b/server/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; diff --git a/routes/orderRoutes.js b/server/routes/orderRoutes.js similarity index 100% rename from routes/orderRoutes.js rename to server/routes/orderRoutes.js diff --git a/routes/productRoutes.js b/server/routes/productRoutes.js similarity index 100% rename from routes/productRoutes.js rename to server/routes/productRoutes.js diff --git a/routes/wishlistRoutes.js b/server/routes/wishlistRoutes.js similarity index 96% rename from routes/wishlistRoutes.js rename to server/routes/wishlistRoutes.js index 29fd0978..8ea62557 100644 --- a/routes/wishlistRoutes.js +++ b/server/routes/wishlistRoutes.js @@ -1,83 +1,83 @@ -const express = require('express'); -const router = express.Router(); -const { isAuthenticatedUser } = require('../middlewares/auth'); -const Wishlist = require('../models/wishlistSchema'); -const ErrorHandler = require('../utils/errorHandler'); - -// route POST /api/wishlist/add-to-wishlist/:productId -// description Add product to wishlist -// access Private (requires authentication) -router.post('/addtowishlist/:productId', isAuthenticatedUser, async (req, res, next) => { - try { - const { productId } = req.params; - const userId = req.body.user.id; // Retrieve user ID from request body - // console.log("inadd to wishlist") - - // Check if the product is already in the user's wishlist - const existingWishlistItem = await Wishlist.findOne({ user: userId, product: productId }); - - if (existingWishlistItem) { - return next(new ErrorHandler('Product is already in your wishlist', 400)); - } - - // Create a new wishlist item - const newWishlistItem = await Wishlist.create({ - user: userId, - product: productId, - }); - - res.status(200).json({ - success: true, - message: 'Product added to wishlist successfully', - wishlistItem: newWishlistItem, - }); - } catch (error) { - next(error); - } -}); - -// route DELETE /api/wishlist/remove-from-wishlist/:productId -// description Remove product from wishlist -// access Private (requires authentication) -router.delete('/removefromwishlist/:productId', isAuthenticatedUser, async (req, res, next) => { - try { - const { productId } = req.params; - const userId = req.body.user.id; - - // Find and delete the wishlist item - const deletedWishlistItem = await Wishlist.findOneAndDelete({ user: userId, product: productId }); - - if (!deletedWishlistItem) { - return next(new ErrorHandler('Product not found in your wishlist', 404)); - } - - res.status(200).json({ - success: true, - message: 'Product removed from wishlist successfully', - wishlistItem: deletedWishlistItem, - }); - } catch (error) { - next(error); - } -}); - -// route GET /api/wishlist -// description Get user's wishlist -// access Private (requires authentication) -router.get('/getwishlistdata', isAuthenticatedUser, async (req, res, next) => { - try { - const userId = req.body.user.id; - - // Fetch user's wishlist items - const wishlistItems = await Wishlist.find({ user: userId }).populate('product'); - - res.status(200).json({ - success: true, - wishlistItems, - }); - } catch (error) { - next(error); - } -}); - -module.exports = router; +const express = require('express'); +const router = express.Router(); +const { isAuthenticatedUser } = require('../middlewares/auth'); +const Wishlist = require('../models/wishlistSchema'); +const ErrorHandler = require('../utils/errorHandler'); + +// route POST /api/wishlist/add-to-wishlist/:productId +// description Add product to wishlist +// access Private (requires authentication) +router.post('/addtowishlist/:productId', isAuthenticatedUser, async (req, res, next) => { + try { + const { productId } = req.params; + const userId = req.body.user.id; // Retrieve user ID from request body + // console.log("inadd to wishlist") + + // Check if the product is already in the user's wishlist + const existingWishlistItem = await Wishlist.findOne({ user: userId, product: productId }); + + if (existingWishlistItem) { + return next(new ErrorHandler('Product is already in your wishlist', 400)); + } + + // Create a new wishlist item + const newWishlistItem = await Wishlist.create({ + user: userId, + product: productId, + }); + + res.status(200).json({ + success: true, + message: 'Product added to wishlist successfully', + wishlistItem: newWishlistItem, + }); + } catch (error) { + next(error); + } +}); + +// route DELETE /api/wishlist/remove-from-wishlist/:productId +// description Remove product from wishlist +// access Private (requires authentication) +router.delete('/removefromwishlist/:productId', isAuthenticatedUser, async (req, res, next) => { + try { + const { productId } = req.params; + const userId = req.body.user.id; + + // Find and delete the wishlist item + const deletedWishlistItem = await Wishlist.findOneAndDelete({ user: userId, product: productId }); + + if (!deletedWishlistItem) { + return next(new ErrorHandler('Product not found in your wishlist', 404)); + } + + res.status(200).json({ + success: true, + message: 'Product removed from wishlist successfully', + wishlistItem: deletedWishlistItem, + }); + } catch (error) { + next(error); + } +}); + +// route GET /api/wishlist +// description Get user's wishlist +// access Private (requires authentication) +router.get('/getwishlistdata', isAuthenticatedUser, async (req, res, next) => { + try { + const userId = req.body.user.id; + + // Fetch user's wishlist items + const wishlistItems = await Wishlist.find({ user: userId }).populate('product'); + + res.status(200).json({ + success: true, + wishlistItems, + }); + } catch (error) { + next(error); + } +}); + +module.exports = router; diff --git a/utils/errorHandler.js b/server/utils/errorHandler.js similarity index 100% rename from utils/errorHandler.js rename to server/utils/errorHandler.js diff --git a/utils/jwtToken.js b/server/utils/jwtToken.js similarity index 100% rename from utils/jwtToken.js rename to server/utils/jwtToken.js