diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..230b685 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "cSpell.words": ["Cloudinary"] +} diff --git a/client/src/components/user/userDetails.jsx/UserDetails.jsx b/client/src/components/user/userDetails.jsx/UserDetails.jsx index 40e7ca7..612a5c7 100644 --- a/client/src/components/user/userDetails.jsx/UserDetails.jsx +++ b/client/src/components/user/userDetails.jsx/UserDetails.jsx @@ -35,15 +35,18 @@ const UserDetails = () => { { label: "Phone Number", placeholder: "Phone Number", name: "phone", type: "tel" }, { label: "Email", placeholder: "Email", name: "email", type: "email" }, { label: "Address", placeholder: "Address", name: "address", type: "textarea" }, - { label: "Height", placeholder: "Height", name: "height", type: "text" }, + { label: "Height", placeholder: "Height in cm eg. 170cm", name: "height", type: "text" }, { label: "Weight", placeholder: "Weight (e.g., 70kg)", name: "weight", type: "text" }, - { label: "Complexion", placeholder: "Complexion", name: "complexion", type: "text" }, - { label: "Education", placeholder: "Education", name: "education", type: "text" }, + { label: "Education", placeholder: "Education", name: "education", type: "text" }, + { label: "Religion", placeholder: "Religion", name: "religion", type: "text" }, { label: "Occupation", placeholder: "Occupation", name: "occupation", type: "text" }, { label: "Annual Income", placeholder: "Annual Income", name: "income", type: "text" }, - { label: "Preferred Age Range", placeholder: "Preferred Age Range", name: "preferredAge", type: "text" }, - { label: "Preferred Height Range", placeholder: "in feet", name: "preferredHeight", type: "text" }, - { label: "Preferred Education", placeholder: "Preferred Education", name: "preferredEducation", type: "text" }, + { label: "Preferred Age Range", placeholder: "Preferred Age Range", name: "preferredAge", type: "select", options: ["18-25", "26-35", "36-45", "46+"], }, + { label: "Preferred Height Range", placeholder: "Preferred Height Range", name: "preferredHeight", type: "select", options: ["Short", "Average", "Tall"], }, + { label: "Preferred Education", placeholder: "Preferred Education", name: "preferredEducation", type: "select", options: ["High School", "Bachelor's Degree", "Master's Degree", "PhD"], }, + { label: "Preferred Religion", placeholder: "Preferred Religion", name: "preferredReligion", type: "select", options: ["Islam", "Christianity", "Hinduism", "Buddhism", "Judaism", "Other"], }, + { label: "Preferred Complexion", placeholder: "Preferred Complexion", name: "preferredComplexion", type: "select", options: ["Fair", "Medium", "Dark"], }, + { label: "Preferred Profession", placeholder: "Preferred Profession", name: "preferredProfession", type: "text" }, ]; diff --git a/server/app.js b/server/app.js index 05c3db3..b6629b7 100644 --- a/server/app.js +++ b/server/app.js @@ -2,16 +2,24 @@ import express from "express"; import cors from "cors"; import session from "express-session"; import passport from "passport"; +import fileUpload from "express-fileupload"; import errorHandler from "./src/middleware/errorHandling.middleware.js"; - import { AuthRouter } from "./src/routes/auth.routes.js"; +import { AuthRouter } from "./src/routes/auth.routes.js"; +import { userDetailsRouter } from "./src/routes/user.routes.js"; import "./src/utils/auth.utils.js"; // Initialize Passport.js - + const app = express(); /* MIDDLEWARE */ -app.use(cors()) +app.use(cors()); app.use(express.json()); app.use(express.urlencoded({ extended: true })); +app.use( + fileUpload({ + useTempFiles: true, + tempFileDir: "/tmp/", + }) +); // Configure express-session middleware app.use( @@ -26,12 +34,11 @@ app.use( app.use(passport.initialize()); app.use(passport.session()); -/* ERROR HANDLER */ -app.use(errorHandler); - - /* ROUTES */ - app.use("/auth", AuthRouter); //we added here google auth +app.use("/auth", AuthRouter); +app.use("/user", userDetailsRouter); +/* ERROR HANDLER */ +app.use(errorHandler); export default app; diff --git a/server/package-lock.json b/server/package-lock.json index 23a23a2..38744f5 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -14,6 +14,7 @@ "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.19.2", + "express-fileupload": "^1.5.0", "express-session": "^1.18.0", "jsonwebtoken": "^9.0.2", "mongoose": "^8.4.0", @@ -291,6 +292,17 @@ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -644,6 +656,17 @@ "node": ">= 0.10.0" } }, + "node_modules/express-fileupload": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/express-fileupload/-/express-fileupload-1.5.0.tgz", + "integrity": "sha512-jSW3w9evqM37VWkEPkL2Ck5wUo2a8qa03MH+Ou/0ZSTpNlQFBvSLjU12k2nYcHhaMPv4JVvv6+Ac1OuLgUZb7w==", + "dependencies": { + "busboy": "^1.6.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/express-session": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.0.tgz", @@ -2071,6 +2094,14 @@ "node": ">= 0.8" } }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", diff --git a/server/package.json b/server/package.json index bb820a0..b9705fd 100644 --- a/server/package.json +++ b/server/package.json @@ -16,6 +16,7 @@ "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.19.2", + "express-fileupload": "^1.5.0", "express-session": "^1.18.0", "jsonwebtoken": "^9.0.2", "mongoose": "^8.4.0", diff --git a/server/server.js b/server/server.js index 055c5bf..1630277 100644 --- a/server/server.js +++ b/server/server.js @@ -8,9 +8,7 @@ import { connectDB } from "./src/db/connectDB.js"; app.get("/home", (req, res) => { res.send("hello world"); }); - - - + const startServer = async () => { try { await connectDB(); diff --git a/server/src/controllers/userDetails.controller.js b/server/src/controllers/userDetails.controller.js new file mode 100644 index 0000000..64459e7 --- /dev/null +++ b/server/src/controllers/userDetails.controller.js @@ -0,0 +1,89 @@ +import UserDetails from "../models/userDetails.models.js"; +import { v2 as cloudinary } from "cloudinary"; + +cloudinary.config({ + cloud_name: process.env.CLOUDINARY_CLOUD_NAME, + api_key: process.env.CLOUDINARY_API_KEY, + api_secret: process.env.CLOUDINARY_API_SECRET, +}); + +const createUserDetails = async (req, res, next) => { + const { + firstName, + fathersName, + surname, + mothersName, + age, + gender, + address, + dob, + phoneNumber, + email, + education, + religion, + martialStatus, + occupation, + annualIncome, + preferredAgeRange, + preferredHeightRange, + preferredEducation, + preferredComplexion, + preferredProfession, + preferredLocation, + } = req.body; + + try { + let profileUrl = ""; + + // Check if a file is uploaded + if (req.files && req.files.profileImage) { + const file = req.files.profileImage; + + // Upload file to Cloudinary + const uploadResult = await cloudinary.uploader.upload(file.tempFilePath, { + public_id: `user_profiles/${file.name}`, + }); + + profileUrl = uploadResult.secure_url; + } + + // Ensure profileUrl is not empty + if (!profileUrl) { + throw new Error("Profile image upload failed or not provided"); + } + + // Create new user details + const newUserDetails = new UserDetails({ + yourProfileUrl: profileUrl, + firstName, + fathersName, + surname, + mothersName, + age, + gender, + address, + dob, + phoneNumber, + email, + education, + religion, + martialStatus, + occupation, + annualIncome, + preferredAgeRange, + preferredHeightRange, + preferredEducation, + preferredComplexion, + preferredProfession, + preferredLocation, + }); + + await newUserDetails.save(); + + res.status(201).json(newUserDetails); + } catch (error) { + next(error); + } +}; + +export { createUserDetails }; diff --git a/server/src/middleware/auth.middleware.js b/server/src/middleware/auth.middleware.js index bc878a6..3ad83b9 100644 --- a/server/src/middleware/auth.middleware.js +++ b/server/src/middleware/auth.middleware.js @@ -5,6 +5,6 @@ export const authenticateGoogle = passport.authenticate("google", { }); export const googleCallback = passport.authenticate("google", { - failureRedirect: "/", - successRedirect: "/dashboard", // Adjust the redirect URL as needed + failureRedirect: "/login", + successRedirect: "/home", //adjust based on success }); diff --git a/server/src/models/userDetails.models.js b/server/src/models/userDetails.models.js new file mode 100644 index 0000000..94ab8ac --- /dev/null +++ b/server/src/models/userDetails.models.js @@ -0,0 +1,92 @@ +import mongoose from "mongoose"; + +const userDetailsSchema = new mongoose.Schema( + { + yourProfileUrl: { + type: String, + required: true, + }, + firstName: { + type: String, + required: true, + }, + fathersName: { + type: String, + required: true, + }, + surname: String, + mothersName: String, + age: { + type: Number, + min: 18, + max: 120, + }, + gender: { + type: String, + enum: ["Male", "Female", "Other"], + }, + dob: { + type: Date, + required: true, + }, + phoneNumber: { + type: String, + match: /^\d{10}$/, + required: true, + }, + email: { + type: String, + required: true, + unique: true, + lowercase: true, + match: /^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,7}$/, + }, + address: String, + height: String, + weight: String, + education: { + type: String, + enum: [ + "High School", + "Bachelor's Degree", + "Master's Degree", + "PhD", + "Other", + ], + }, + religion: String, + martialStatus: { + type: String, + enum: ["unmarried", "divorced"], + }, + occupation: String, + annualIncome: String, + preferredAgeRange: { + type: String, + enum: ["18-25", "26-35", "36-45", "46+"], + }, + preferredHeightRange: String, + preferredEducation: { + type: String, + enum: [ + "High School", + "Bachelor's Degree", + "Master's Degree", + "PhD", + "Other", + ], + }, + preferredReligion: String, + preferredComplexion: { + type: String, + enum: ["Fair", "Medium", "Dark"], + }, + preferredProfession: String, + preferredLocation: String, + }, + { timestamps: true } +); + +const UserDetails = mongoose.model("UserDetails", userDetailsSchema); + +export default UserDetails; diff --git a/server/src/routes/user.routes.js b/server/src/routes/user.routes.js new file mode 100644 index 0000000..a11ab97 --- /dev/null +++ b/server/src/routes/user.routes.js @@ -0,0 +1,9 @@ +import express from "express"; +import { createUserDetails } from "../controllers/userDetails.controller.js"; + +const router = express.Router(); + +// Define your routes here +router.post("/createUserDetails", createUserDetails); + +export const userDetailsRouter = router;