diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 8dbe145..0345064 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1,33 +1,32 @@
Please include a summary of the changes and the related issue. Please also include relevant motivation and context. List any dependencies that are required for this change.
-
Fixes # (issue)
-
## Type of change
-Please give a X on it which is applicable
+Please mark with an X the type that applies:
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
-- [ ] Refactor Code
-- [ ] A documentation update
-- [ ] Others(mentioned in the issue number)
+- [ ] Refactor code
+- [ ] Documentation update
+- [ ] Other (mentioned in the issue number)
# How Has This Been Tested?
-Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration
+Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce them. Please also list any relevant details for your test configuration.
+
+**_Test A: Describe here_**
-**_Test A Describe here_**
+**_Test B: Describe here (if required)_**
-**_Test B Describe here (if Requred)_**
+# Screenshots and Videos
-# Screenshorts and Vedios:
+Please provide screenshots and videos of the changes you made.
-give screenshorts and vedio of the changes you made
+# Checklist
-# Checklist:
-give a X on it which is applicable
+Please mark with an X the items that apply:
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my code
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d78ebfe
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 Vansh Waldeo
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
index 361f5b6..73d5ed3 100644
--- a/README.md
+++ b/README.md
@@ -108,7 +108,16 @@ Welcome to Foodies, your go-to college dining companion! Designed for seamless c
```
PORT=3000
DATABASE_URL="http://localhost:21713/foods"
+ EMAIL="The email from which forgot the password email will be sent"
+ MAILPASS="password for the email ( app password )"
```
+ ### **STEP TO GENERATE APP PASSWORD**
+ 1) Enable 2-step verification if not
+ **In https://myaccount.google.com/security, do you see 2-step verification set to ON**
+
+ 2) Generate APP PASSWORD by clicking on below link
+ **https://myaccount.google.com/apppasswords?rapt=AEjHL4PAhcbtFEpLwfNtVix3bfiGe71GdrW_Naiuvp_NVnMZyTd0UR07M2mVnEyWzkw9kB99YVhhfEVtjxTi3QWSZ39biK-zGwnghm0u778vwmlh6TFbmh4**
+
6. **Start the Backend Server (in the terminal within the /server directory):**
In the terminal where you navigated to the /server directory, run the following command to start the backend server:
diff --git a/package.json b/package.json
index e33361c..33d7efb 100644
--- a/package.json
+++ b/package.json
@@ -3,6 +3,8 @@
"version": "0.1.0",
"private": true,
"dependencies": {
+ "@emailjs/browser": "^4.3.3",
+ "@react-icons/all-files": "^4.1.0",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
@@ -12,7 +14,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hot-toast": "^2.4.1",
- "react-icons": "^4.11.0",
+ "react-icons": "^4.12.0",
"react-icons-kit": "^2.0.0",
"react-modal": "^3.16.1",
"react-router-dom": "^6.16.0",
diff --git a/public/c4.png b/public/c4.png
new file mode 100644
index 0000000..1b66139
Binary files /dev/null and b/public/c4.png differ
diff --git a/public/i9.png b/public/i9.png
new file mode 100644
index 0000000..597b3c6
Binary files /dev/null and b/public/i9.png differ
diff --git a/server/config/cloudinaryConfig.js b/server/config/cloudinaryConfig.js
index cf949e4..e8139fb 100644
--- a/server/config/cloudinaryConfig.js
+++ b/server/config/cloudinaryConfig.js
@@ -1,14 +1,26 @@
-const config = require("cloudinary").config;
-const uploader = require("cloudinary").uploader;
-const dotenv = require("dotenv");
+const cloudinary = require('cloudinary').v2;
+const dotenv = require('dotenv');
dotenv.config();
const cloudinaryConfig = (req, res, next) => {
- config({
+ cloudinary.config({
cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET,
});
next();
};
-module.exports = { cloudinaryConfig, uploader };
+
+const uploadImage = async (filePath) => {
+ try {
+ const result = await cloudinary.uploader.upload(filePath, {
+ folder: 'canteen_images', // Specify the folder where images should be uploaded
+ });
+ return result;
+ } catch (error) {
+ throw new Error('Error uploading image to Cloudinary');
+ }
+};
+
+module.exports = { cloudinaryConfig, uploadImage };
+
diff --git a/server/config/database.js b/server/config/database.js
index 820c338..44cfef0 100644
--- a/server/config/database.js
+++ b/server/config/database.js
@@ -5,7 +5,6 @@ require("dotenv").config();
const dbConnect = () =>{
mongoose.connect(process.env.DATABASE_URL,{
-
useNewUrlParser : true,
useUnifiedTopology : true,
})
diff --git a/server/controllers/Auth.js b/server/controllers/Auth.js
index 085ed28..57982fa 100644
--- a/server/controllers/Auth.js
+++ b/server/controllers/Auth.js
@@ -3,15 +3,33 @@ const User = require("../models/studentLoginInfo");
const jwt = require("jsonwebtoken");
const Canteen = require("../models/canteenLoginInfo");
const Session = require("../models/session");
-
+const Contact = require('../models/Contact');
+const {
+ forgotPasswordToken,
+ verifyToken,
+ findUserByEmail,
+ findUserById,
+} = require("../utils/PasswordTokenAndUser");
+const nodemailer = require("nodemailer");
require("dotenv").config();
exports.studentSignup = async (req, res) => {
console.log("This is jwt", process.env.JWT_SECRET);
try {
console.log(req.body);
- const { name, email, collegeName, accountType, password } = await req.body;
- const existingUser = await User.findOne({ email });
+ const { name, email, collegeName, accountType, password, confirmPassword } =
+ await req.body;
+
+ if (password !== confirmPassword) {
+ return res.status(400).json({
+ success: false,
+ message: "Password and Confirm password didn't match, try again",
+ });
+ }
+
+ const existingUser = await User.findOne({
+ email,
+ });
if (existingUser) {
return res.status(400).json({
@@ -87,7 +105,10 @@ exports.studentLogin = async (req, res) => {
});
// creating a session
- const session = new Session({ userId: user._id, token });
+ const session = new Session({
+ userId: user._id,
+ token,
+ });
await session.save();
user = user.toObject();
@@ -107,14 +128,20 @@ exports.studentLogin = async (req, res) => {
// message: "User logged in succesfully",
// });
- // Setting cookie
+ // Setting cookie
res.cookie("token", token, {
httpOnly: true,
secure: true,
maxAge: 3600000,
});
- res.json({ success: true, message: "Logged in successfully", token, user });
+ res.json({
+ success: true,
+ message: "Logged in successfully",
+ token,
+ user,
+ });
} else {
+
return res.status(403).json({
success: false,
message: "Pasword Incorrect",
@@ -161,7 +188,10 @@ exports.studentLogout = async (req, res) => {
await Session.findOneAndDelete({ token });
res.clearCookie("token");
}
- res.status(200).json({ success: true, message: "Logged out successfully" });
+ res.status(200).json({
+ success: true,
+ message: "Logged out successfully",
+ });
} catch (error) {
console.log(error);
return res.status(500).json({
@@ -233,9 +263,13 @@ exports.canteenSignup = async (req, res) => {
});
// Create a token
- const token = jwt.sign({ id: canteen._id, email: canteen.email }, process.env.JWT_SECRET, {
- expiresIn: '1h', // Set token expiration time as needed
- });
+ const token = jwt.sign(
+ { id: canteen._id, email: canteen.email },
+ process.env.JWT_SECRET,
+ {
+ expiresIn: "1h", // Set token expiration time as needed
+ }
+ );
console.log("User created successfully with ID:", canteen._id);
return res.status(200).json({
@@ -263,7 +297,9 @@ exports.canteenLogin = async (req, res) => {
});
}
- let canteen = await Canteen.findOne({ email });
+ let canteen = await Canteen.findOne({
+ email,
+ });
if (!canteen) {
return res.status(401).json({
success: false,
@@ -301,7 +337,10 @@ exports.canteenLogin = async (req, res) => {
// });
// Create session
- const session = new Session({ userId: canteen._id, token });
+ const session = new Session({
+ userId: canteen._id,
+ token,
+ });
await session.save();
// Set cookie
@@ -310,8 +349,13 @@ exports.canteenLogin = async (req, res) => {
secure: true,
maxAge: 3600000,
});
- res.json({ success: true, message: "Logged in successfully", token, canteen, cantId: canteen._id });
-
+ res.json({
+ success: true,
+ message: "Logged in successfully",
+ token,
+ canteen,
+ cantId: canteen._id,
+ });
} else {
return res.status(403).json({
success: false,
@@ -359,7 +403,10 @@ exports.canteenLogout = async (req, res) => {
await Session.findOneAndDelete({ token });
res.clearCookie("token");
}
- res.status(200).json({ success: true, message: "Logged out successfully" });
+ res.status(200).json({
+ success: true,
+ message: "Logged out successfully",
+ });
} catch (error) {
console.log(error);
return res.status(500).json({
@@ -393,3 +440,158 @@ exports.changeCanteenPassword = async (req, res) => {
message: "Password updated successfully.",
});
};
+
+//contactUs
+
+exports.saveContactMessage = async (req, res) => {
+ try {
+ const { name, email, message } = req.body;
+ if (!name || !email || !message) {
+ return res.status(400).send('All fields are required');
+ }
+ const newContact = new Contact({ name, email, message });
+ await newContact.save();
+ res.status(201).send('Message received');
+ } catch (error) {
+ console.error('Error saving message:', error.message, error);
+ res.status(500).send('Error saving message');
+ }
+};
+// verify user for reset password
+exports.forgotPassword = async (req, res) => {
+ try {
+ const { email } = req.body;
+ const existingUser = await findUserByEmail(email);
+
+ if (!existingUser) {
+ return res.status(400).json({
+ success: false,
+ message: "User does not exist",
+ });
+ } else {
+ const tokenReturn = forgotPasswordToken(existingUser);
+ // const link = `http://localhost:3000/api/v1/newPassword/${existingUser._id}/${tokenReturn}`;
+
+ const link = `https://foodies-web-app.vercel.app/api/v1/newPassword/${existingUser._id}/${tokenReturn}`;
+
+ const transporter = nodemailer.createTransport({
+ service: "gmail",
+ auth: {
+ user: process.env.EMAIL,
+ pass: process.env.MAILPASS,
+ },
+ });
+
+ const mailOptions = {
+ from: process.env.EMAIL,
+ to: email,
+ subject: "Password Reset Link",
+ html: `
+
+
Password Reset Request
+
Hello,
+
You have requested to reset your password. Please click the button below to reset your password:
+
+
If you did not request this, please ignore this email.
+
Thank you,
+
FoodiesWeb
+
+
© 2024 Your Company Name. All rights reserved.
+
+ `,
+ };
+
+ await transporter.sendMail(mailOptions, function (error, info) {
+ if (error) {
+ console.log(error);
+ }
+ });
+
+ res.status(201).json({
+ msg: "You should receive an email",
+ });
+ }
+ } catch (error) {
+ console.error(error);
+ return res.status(500).json({
+ success: false,
+ message: "User verification failed",
+ });
+ }
+};
+
+//for verification of link
+exports.verifyLink = async (req, res) => {
+ const { id, token } = req.params;
+ console.log(req.params);
+
+ const oldUser = await findUserById(id);
+ if (!oldUser) {
+ return res.status(404).json({
+ success: false,
+ message: "User not found!",
+ });
+ }
+
+ try {
+ console.log("Found user: ", oldUser);
+ const verify = verifyToken(oldUser, token);
+ console.log("VerifyToken result: ", verify);
+
+ if (verify.id === id) {
+ res.status(201).json({
+ email: verify.email,
+ status: "Verified",
+ });
+ } else {
+ res.status(201).json({
+ status: "Cannot Verify",
+ });
+ }
+ } catch (error) {
+ res.status(201).json({
+ status: "Not Verified",
+ });
+ }
+};
+
+exports.resetPassword = async (req, res) => {
+ const { id, token } = req.params;
+ const { password } = req.body;
+
+ console.log(password, " ", id, " ", token);
+
+ try {
+ const oldUser = await findUserById(id);
+
+ if (!oldUser) {
+ return res.status(404).json("User not found");
+ }
+
+ const verify = verifyToken(oldUser, token);
+ if (verify.id !== id) {
+ return res.status(201).json({ change: false });
+ }
+
+ const salt = await bcrypt.genSalt(10);
+ const newPassword = await bcrypt.hash(password, salt);
+
+ if (oldUser instanceof User) {
+ await User.findByIdAndUpdate(id, {
+ password: newPassword,
+ });
+ } else if (oldUser instanceof Canteen) {
+ await Canteen.findByIdAndUpdate(id, {
+ password: newPassword,
+ });
+ }
+
+ res.status(201).json({ change: true });
+ } catch (error) {
+ console.log("Error while changing password: ", error);
+ res.status(500).json("Some error occurred!");
+ }
+};
+
diff --git a/server/controllers/canteenController.js b/server/controllers/canteenController.js
index 41eba08..e36b07c 100644
--- a/server/controllers/canteenController.js
+++ b/server/controllers/canteenController.js
@@ -3,6 +3,7 @@ const Breakfast = require('../models/breakfast');
const Lunch = require('../models/lunch');
const Dinner = require('../models/dinner');
const Canteen = require("../models/canteenLoginInfo");
+const { uploader } = require('../config/cloudinaryConfig');
@@ -27,7 +28,7 @@ const getBreakfast = async(req , res , next) =>{
try{
const id = req.params.id;
- console.log(id);
+
const breakfastData = await Breakfast.find({ canteen: id }).select("dish").select("dishId").exec();
@@ -117,9 +118,9 @@ const addBreakfastDish = asyncHandler(async (req, res, next) => {
// Controller function to remove a breakfast dish
const removeBreakfastDish = asyncHandler(async (req, res, next) => {
const canteenId = req.params.id;
- const { dish } = req.body;
+ const dish = req.body._id;
- await Breakfast.deleteOne({ canteen: canteenId, dish }).exec();
+ await Breakfast.deleteOne({ _id:dish }).exec();
res.json({ message: 'Dish removed successfully' });
});
@@ -146,9 +147,9 @@ const addLunchDish = asyncHandler(async (req, res, next) => {
// Controller function to remove a lunch dish
const removeLunchDish = asyncHandler(async (req, res, next) => {
const canteenId = req.params.id;
- const { dish } = req.body;
+ const dish = req.body._id;
- await Lunch.deleteOne({ canteen: canteenId, dish }).exec();
+ await Lunch.deleteOne({ _id:dish }).exec();
res.json({ message: 'Dish removed successfully' });
});
@@ -174,12 +175,111 @@ const addDinnerDish = asyncHandler(async (req, res, next) => {
// Controller function to remove a dinner dish
const removeDinnerDish = asyncHandler(async (req, res, next) => {
const canteenId = req.params.id;
- const { dish } = req.body;
+ const dish = req.body._id;
- await Dinner.deleteOne({ canteen: canteenId, dish }).exec();
+ await Dinner.deleteOne({ _id:dish }).exec();
res.json({ message: 'Dish removed successfully' });
});
+// Controller function to update canteen details
+
+
+const updateCanteen = async (req, res, next) => {
+ try {
+ const canteenId = req.params.id;
+ const { name, email, collegeName, canteenImage } = req.body;
+
+ // Process the uploaded file if exists
+ if (req.file) {
+ const filePath = `public/uploads/${req.file.originalname}`;
+ const uploadedImage = await uploader.upload(filePath);
+ req.body.canteenImage = uploadedImage.url; // Update the canteenImage with the uploaded file URL
+ }
+
+ // Find the canteen by ID and update
+ const canteen = await Canteen.findByIdAndUpdate(canteenId, req.body, { new: true });
+
+ // If canteen not found, return error
+ if (!canteen) {
+ return res.status(404).json({ success: false, message: "Canteen not found" });
+ }
+
+ // Return success response
+ res.status(200).json({ success: true, message: "Canteen updated successfully", data: canteen });
+ } catch (error) {
+ // Handle errors
+ console.error("Error updating canteen:", error);
+ res.status(500).json({ success: false, error: "Internal Server Error" });
+ }
+};
+//controller to update Canteen FoddItem Details
+
+
+// Controller function to update a breakfast dish
+const updateBreakfastDish = asyncHandler(async (req, res, next) => {
+ const canteenId = req.params.id;
+ const { dishId, dish } = req.body;
+
+ try {
+ const updatedDish = await Breakfast.findOneAndUpdate(
+ { _id: dishId, canteen: canteenId },
+ { $set: { dish } },
+ { new: true }
+ ).exec();
+
+ if (!updatedDish) {
+ return res.status(404).json({ message: 'Dish not found' });
+ }
+
+ res.json({ message: 'Dish updated successfully', data: updatedDish });
+ } catch (error) {
+ res.status(500).json({ success: false, error: error.message });
+ }
+});
+//Controller to update Lunch
+const updateLunchDish = asyncHandler(async (req, res, next) => {
+ const canteenId = req.params.id;
+ const { dishId, dish } = req.body;
+
+ try {
+ const updatedDish = await Lunch.findOneAndUpdate(
+ { _id: dishId, canteen: canteenId },
+ { $set: { dish } },
+ { new: true }
+ ).exec();
+
+ if (!updatedDish) {
+ return res.status(404).json({ message: 'Dish not found' });
+ }
+
+ res.json({ message: 'Dish updated successfully', data: updatedDish });
+ } catch (error) {
+ res.status(500).json({ success: false, error: error.message });
+ }
+});
+//Controller to update dinner
+
+const updateDinnerDish = asyncHandler(async (req, res, next) => {
+ const canteenId = req.params.id;
+ const { dishId, dish } = req.body;
+
+ try {
+ const updatedDish = await Dinner.findOneAndUpdate(
+ { _id: dishId, canteen: canteenId },
+ { $set: { dish } },
+ { new: true }
+ ).exec();
+
+ if (!updatedDish) {
+ return res.status(404).json({ message: 'Dish not found' });
+ }
+
+ res.json({ message: 'Dish updated successfully', data: updatedDish });
+ } catch (error) {
+ res.status(500).json({ success: false, error: error.message });
+ }
+});
+
module.exports = {
getCanteenDashboard,
@@ -193,4 +293,8 @@ module.exports = {
getBreakfast,
getLunch,
getDinner,
+ updateCanteen,
+ updateBreakfastDish,
+ updateLunchDish,
+ updateDinnerDish,
};
diff --git a/server/middleware/multer.middleware.js b/server/middleware/multer.middleware.js
index a385092..a294166 100644
--- a/server/middleware/multer.middleware.js
+++ b/server/middleware/multer.middleware.js
@@ -1,5 +1,8 @@
-const multer = require("multer");
+const multer = require('multer');
const storage = multer.memoryStorage();
-const multerUploads = multer({ storage }).single("image");
+const multerUploads = multer({
+ storage,
+ limits: { fileSize: 50 * 1024 * 1024 } // Set limit to 50MB
+}).single("image");
module.exports = multerUploads;
diff --git a/server/models/Contact.js b/server/models/Contact.js
new file mode 100644
index 0000000..b82aeb7
--- /dev/null
+++ b/server/models/Contact.js
@@ -0,0 +1,11 @@
+const mongoose = require('mongoose');
+
+const contactSchema = new mongoose.Schema({
+ name: { type: String, required: true },
+ email: { type: String, required: true },
+ message: { type: String, required: true },
+});
+
+const Contact = mongoose.model('Contact', contactSchema);
+
+module.exports = Contact;
diff --git a/server/models/canteenLoginInfo.js b/server/models/canteenLoginInfo.js
index af22b92..d75ac33 100644
--- a/server/models/canteenLoginInfo.js
+++ b/server/models/canteenLoginInfo.js
@@ -14,15 +14,18 @@ const canteenSchema = new Schema({
type: String,
required: true,
},
- accountType : {
- type : String,
- enum : ["User" , "Canteen"],
- required : true,
+ accountType: {
+ type: String,
+ enum: ["User", "Canteen"],
+ required: true,
},
password: {
type: String,
required: true,
},
+ canteenImage: {
+ type: String, // Assuming you're storing the URL or base64 string of the image
+ },
});
const Canteen = mongoose.model('Canteen', canteenSchema);
diff --git a/server/package.json b/server/package.json
index 38bb8fe..9875b1c 100644
--- a/server/package.json
+++ b/server/package.json
@@ -17,13 +17,14 @@
"cors": "^2.8.5",
"datauri": "^4.1.0",
"dotenv": "^16.4.5",
- "express": "^4.18.2",
+ "express": "^4.19.2",
"express-async-handler": "^1.2.0",
"faker": "^5.5.3",
"jsonwebtoken": "^9.0.2",
- "mongoose": "^7.6.2",
+ "mongoose": "^7.6.13",
"multer": "^1.4.5-lts.1",
- "nodemon": "^3.0.1",
+ "nodemailer": "^6.9.13",
+ "nodemon": "^3.1.3",
"path": "^0.12.7"
}
}
diff --git a/server/routes/canteen.js b/server/routes/canteen.js
index e4b574e..83e6242 100644
--- a/server/routes/canteen.js
+++ b/server/routes/canteen.js
@@ -4,6 +4,7 @@ const router = express.Router();
// Import canteen controller functions
const canteenController = require('../controllers/canteenController');
const { auth, isCanteen } = require('../middlewares/auth');
+const multerUploads = require('../middleware/multer.middleware');
router.get('/getcanteen' , canteenController.getAllCanteen);
@@ -37,4 +38,12 @@ router.post('/:id/dinner/add',auth,isCanteen, canteenController.addDinnerDish);
// Route to remove a dinner dish for a specific canteen
router.delete('/:id/dinner/remove',auth,isCanteen, canteenController.removeDinnerDish);
+//router to update profile
+router.put('/:id/update', auth, isCanteen, multerUploads, canteenController.updateCanteen);
+
+// New update routes
+router.put('/:id/breakfast/updateitem',auth,isCanteen, canteenController.updateBreakfastDish);
+router.put('/:id/lunch/updateitem',auth,isCanteen, canteenController.updateLunchDish);
+router.put('/:id/dinner/updateitem',auth,isCanteen, canteenController.updateDinnerDish);
+
module.exports = router;
diff --git a/server/routes/contactRoutes.js b/server/routes/contactRoutes.js
new file mode 100644
index 0000000..c7fcc7e
--- /dev/null
+++ b/server/routes/contactRoutes.js
@@ -0,0 +1,7 @@
+const express = require('express');
+const { saveContactMessage } = require('../controllers/Auth');
+const router = express.Router();
+
+router.post('/', saveContactMessage);
+
+module.exports = router;
diff --git a/server/routes/student.js b/server/routes/student.js
index 3168ac9..e6f2054 100644
--- a/server/routes/student.js
+++ b/server/routes/student.js
@@ -7,6 +7,9 @@ router.post("/studentSignup", authController.studentSignup);
router.post("/studentLogin", authController.studentLogin);
router.post("/canteenSignup", authController.canteenSignup);
router.post("/canteenLogin", authController.canteenLogin);
+router.post("/VerifyUser",authController.forgotPassword);
+router.get("/resetPassword/:id/:token",authController.verifyLink);
+router.post("/newPassword/:id/:token",authController.resetPassword);
router.get("/studentLogout", studentAuth, authController.studentLogout);
router.get("/canteenLogout", auth, authController.canteenLogout);
router.post(
@@ -20,4 +23,5 @@ router.post(
isCanteen,
authController.changeCanteenPassword
);
+
module.exports = router;
diff --git a/server/server.js b/server/server.js
index 0339668..6836f6c 100644
--- a/server/server.js
+++ b/server/server.js
@@ -1,11 +1,11 @@
const express = require("express");
const app = express();
-const dotenv = require('dotenv')
-dotenv.config({path : ".env"});
const cors = require("cors");
var cookieParser = require("cookie-parser");
const PORT = process.env.PORT || 4000;
const cloudinaryConfig = require("./config/cloudinaryConfig");
+const contactRoutes = require('./routes/contactRoutes');
+const bodyParser = require('body-parser');
app.use(
@@ -25,6 +25,7 @@ const uploadFileRouter = require("./routes/uploadFile");
app.use("/api/v1", canteenRoutes);
app.use("/api/v1", studentRoutes);
app.use("/api/v1", uploadFileRouter);
+app.use('/api/contact', contactRoutes);
app.listen(PORT, () => {
console.log(`Server started succesfully at ${PORT}`);
diff --git a/server/utils/PasswordTokenAndUser.js b/server/utils/PasswordTokenAndUser.js
new file mode 100644
index 0000000..a11723b
--- /dev/null
+++ b/server/utils/PasswordTokenAndUser.js
@@ -0,0 +1,51 @@
+const jwt = require("jsonwebtoken");
+const User = require("../models/studentLoginInfo");
+const Canteen = require("../models/canteenLoginInfo");
+
+const forgotPasswordToken = (oldUser) => {
+ const secret =
+ process.env.JWT_SECRET + oldUser.password;
+ const token = jwt.sign(
+ {
+ email: oldUser.email,
+ id: oldUser._id,
+ },
+ secret,
+ {
+ expiresIn: "2m",
+ }
+ );
+ return token;
+};
+
+const verifyToken = (oldUser, token) => {
+ const secret =
+ process.env.JWT_SECRET + oldUser.password;
+ const verify = jwt.verify(token, secret);
+
+ return verify;
+};
+
+const findUserByEmail = async (email) => {
+ let user = await User.findOne({ email });
+ if (!user) {
+ user = await Canteen.findOne({ email });
+ }
+ return user;
+};
+
+const findUserById = async (id) => {
+ let user = await User.findById(id);
+ if (!user) {
+ user = await Canteen.findById(id);
+ }
+ return user;
+};
+
+
+module.exports = {
+ forgotPasswordToken,
+ verifyToken,
+ findUserById,
+ findUserByEmail,
+};
diff --git a/src/App.css b/src/App.css
index 74b5e05..3464378 100644
--- a/src/App.css
+++ b/src/App.css
@@ -12,6 +12,9 @@
animation: App-logo-spin infinite 20s linear;
}
}
+li:hover span {
+ opacity: 1;
+}
.App-header {
background-color: #282c34;
@@ -36,3 +39,7 @@
transform: rotate(360deg);
}
}
+
+.nav-item{
+ font-size: 52px !important;
+}
\ No newline at end of file
diff --git a/src/App.js b/src/App.js
index b82484b..87fc149 100644
--- a/src/App.js
+++ b/src/App.js
@@ -11,8 +11,16 @@ import SectionPage from './pages/SectionPage';
import News from './pages/News';
import NotFound from './pages/NotFound';
import Loader from './components/Loader/Loader';
+import ForgotPassword from './pages/ForgotPassword';
+import ResetPassword from './pages/ResetPassword';
import { ThemeProvider } from './themeContext';
+import ContactUs from './pages/ContactUs';
+
+import { AuthProvider } from './authContext'
+import EditProfile from './pages/EditProfile';
+
+
const Layout = ({ children }) => {
return (
@@ -23,6 +31,7 @@ const Layout = ({ children }) => {
function App() {
return (
+
@@ -30,16 +39,23 @@ function App() {
} />
} />
} />
+ } />
+
+ } />
+ } />
+
} />
} />
} />
} />
} />
} />
+ } />
} />
+
);
}
diff --git a/src/authContext.js b/src/authContext.js
new file mode 100644
index 0000000..4b1fb0b
--- /dev/null
+++ b/src/authContext.js
@@ -0,0 +1,23 @@
+import { createContext, useContext, useState } from "react";
+
+const authContext = createContext({
+ isAuthenticated: false
+});
+
+export const useAuth = () => useContext(authContext);
+
+const AuthProvider = ({ children }) => {
+ const [isAuthenticated, setAuthenticated] = useState(false);
+
+ const checkAuthentication = (token) => {
+ setAuthenticated(!!token);
+ };
+
+ return (
+
+ {children}
+
+ );
+};
+
+export { AuthProvider };
diff --git a/src/components/CanteenCard.jsx b/src/components/CanteenCard.jsx
index 302d38a..b78a9b7 100644
--- a/src/components/CanteenCard.jsx
+++ b/src/components/CanteenCard.jsx
@@ -1,9 +1,27 @@
-import React, { useState } from "react";
+import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";
-import myHotel from "../assets/myHotel.jpg"
+import fetchRandomRestaurantImage from "../utils/unsplash";
+import { ClipLoader } from "react-spinners"; // Import ClipLoader from react-spinners
-const CanteenCard = ({ canteen }) => {
+const CanteenCard = ({ canteen }) => {
const [selectedRecipes, setSelectedRecipes] = useState({});
+ const [imageSrc, setImageSrc] = useState('');
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ const getImage = async () => {
+ try {
+ const imageUrl = await fetchRandomRestaurantImage();
+ setImageSrc(imageUrl);
+ } catch (error) {
+ console.error('Error fetching image:', error);
+ setImageSrc('default-image-url');
+ } finally {
+ setLoading(false);
+ }
+ };
+ getImage();
+ }, []);
const handleAddToMenu = (recipeId) => {
setSelectedRecipes((prevSelectedRecipes) => ({
@@ -14,45 +32,51 @@ const CanteenCard = ({ canteen }) => {
return (
);
};
diff --git a/src/components/FloatBtn/FloatBtn.css b/src/components/FloatBtn/FloatBtn.css
new file mode 100644
index 0000000..d3367f8
--- /dev/null
+++ b/src/components/FloatBtn/FloatBtn.css
@@ -0,0 +1,23 @@
+
+.scrollButton {
+ position: fixed;
+ bottom: 40px;
+ right: 20px;
+ background-color: #66BB6A;
+ color: white;
+ border: none;
+ border-radius: 50%;
+ width: 45px;
+ height: 45px;
+ font-size: 24px;
+ cursor: pointer;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
+ transition: background-color 0.3s ease;
+ }
+
+ .scrollButton:hover {
+ background-color: #43A047;
+ }
\ No newline at end of file
diff --git a/src/components/FloatBtn/FloatBtn.jsx b/src/components/FloatBtn/FloatBtn.jsx
new file mode 100644
index 0000000..e5decca
--- /dev/null
+++ b/src/components/FloatBtn/FloatBtn.jsx
@@ -0,0 +1,17 @@
+import "./FloatBtn.css";
+
+const FloatBtn = () => {
+ const scrollToTop = () => {
+ window.scrollTo({
+ top: 0,
+ behavior: "smooth"
+ });
+ };
+ return(
+
+ );
+};
+
+export default FloatBtn;
\ No newline at end of file
diff --git a/src/components/Footer.jsx b/src/components/Footer.jsx
index 9256716..45d5c69 100644
--- a/src/components/Footer.jsx
+++ b/src/components/Footer.jsx
@@ -1,45 +1,23 @@
+import { Link } from "react-router-dom"
-import React from 'react';
-import { useNavigate } from 'react-router-dom';
-
-const Footer = () => {
- const navigate = useNavigate();
-
- const handleNavigation = (path) => {
- navigate(path);
- window.scrollTo(0, 0);
- };
- return (
-
-
-
-

-
-
-
-
Company
-
- - handleNavigation('/about')}>About Us
- - News
- - Contact Us
-
-
-
-
-
-
-
© 2024-2025 Foodies™. All Rights Reserved.
-
-
- )
-}
-
-export default Footer
-
+export default function Footer(){
+ return (
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/Modal-update.js b/src/components/Modal-update.js
new file mode 100644
index 0000000..37e99df
--- /dev/null
+++ b/src/components/Modal-update.js
@@ -0,0 +1,40 @@
+
+import React, { useState } from "react";
+
+const Modalupdate = ({ dish, onUpdate, onCancel }) => {
+ const [updatedDish, setUpdatedDish] = useState(dish);
+
+ const handleUpdate = () => {
+ onUpdate(updatedDish);
+ };
+
+ return (
+
+
+
Edit Dish
+
setUpdatedDish(e.target.value)}
+ className="border border-gray-300 p-2 w-full mb-4"
+ />
+
+
+
+
+
+
+ );
+};
+
+export default Modalupdate;
diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx
index 12dd6ef..e6e0351 100644
--- a/src/components/Navbar.jsx
+++ b/src/components/Navbar.jsx
@@ -16,19 +16,21 @@ const Navbar = () => {
};
return (
-