diff --git a/code/client/src/components/ManageProfile.js b/code/client/src/components/ManageProfile.js index 8fc475482..4bd36b3d2 100644 --- a/code/client/src/components/ManageProfile.js +++ b/code/client/src/components/ManageProfile.js @@ -20,7 +20,7 @@ function ManageProfile() { useEffect(() => { apiClient - .get("/manage-profile") // Fetch user profile data from the backend (e.g., /manage-profile) + .get("/api/users/manage-profile") // Fetch user profile data from the backend (e.g., /manage-profile) .then((res) => { setProfileData(res.data); }) @@ -64,7 +64,7 @@ function ManageProfile() { setErrorMessage(''); try { - await apiClient.post("/manage-profile", profileData); + await apiClient.post("/api/users/manage-profile", profileData); console.log("Updating profile") setSuccessMessage('Profile updated!'); } catch (err) { diff --git a/code/client/src/services/apiClient.js b/code/client/src/services/apiClient.js index 1f187bf99..d70899b9d 100644 --- a/code/client/src/services/apiClient.js +++ b/code/client/src/services/apiClient.js @@ -2,12 +2,8 @@ import axios from 'axios'; // console.log("API Base URL:", process.env.REACT_APP_BASE_URL); -const apiClient = axios.create({ - baseURL: 'http://localhost:5000', // Default to localhost for development -}); - // const apiClient = axios.create({ -// baseURL: 'https://peak-performance-backend-394f316db343.herokuapp.com/', // Default to localhost for development +// baseURL: process.env.REACT_APP_BASE_URL || 'http://localhost:5000', // Default to localhost for development // }); // const apiClient = axios.create({ diff --git a/code/server/app.js b/code/server/app.js deleted file mode 100644 index 8dfbd76ad..000000000 --- a/code/server/app.js +++ /dev/null @@ -1,24 +0,0 @@ -// app.js -// This file defines and configures the Express application. - -const express = require('express'); -const cors = require('cors'); -const userRoutes = require('./routes/userRoutes'); // Import user routes -const goalRoutes = require('./routes/goalRoutes'); // Import goal routes - -const app = express(); - -// Middleware -app.use(cors()); -app.use(express.json()); - -// Test route for server status -app.get('/', (req, res) => { - res.send('Server is running...'); -}); - -// Define routes -app.use('/api/users', userRoutes); // All user-related routes -app.use('/api/goals', goalRoutes); // All goal-related routes - -module.exports = app; \ No newline at end of file diff --git a/code/server/controllers/userController.js b/code/server/controllers/userController.js index a57143331..4a1756a8f 100644 --- a/code/server/controllers/userController.js +++ b/code/server/controllers/userController.js @@ -14,93 +14,123 @@ exports.viewUsers = async (req, res) => { // Manage Profile (GET) exports.manageProfile = async (req, res) => { - try { - const userId = req.body.userId || 10001; // This should dynamically come from the request, e.g., req.userId - const userProfile = await User.findOne({ userId }); - - if (!userProfile) { - return res.status(404).json({ error: "User not found" }); + try { + // TO DO: UPDATE THIS TO GRAB USER ID FROM LOCAL STORAGE, rather than hardcode + const userId = 10001 // req.userId; + const userProfile = await User.findOne({ userId }); + if (!userProfile) { + return res.status(404).json({ error: "User not found" }); + } + res.json(userProfile); + } catch (error) { + res.status(500).json({ error: "Server error" }); } - res.json(userProfile); - } catch (error) { - res.status(500).json({ error: "Server error" }); - } }; // Manage Profile (POST) exports.updateProfile = async (req, res) => { - try { + try { const { userId, name, gender, dob, height } = req.body; + // Find user in the database using userId const userProfile = await User.findOne({ userId }); + // Check if user exists if (!userProfile) { return res.status(404).json({ error: "User not found" }); } + // Update the profile with the new values userProfile.name = name; userProfile.gender = gender; userProfile.dob = dob; userProfile.height = height; + // Save the updated user profile await userProfile.save(); + + // Send a success response res.status(200).json({ message: "Profile updated successfully", userProfile }); } catch (error) { + console.error(error); // Log the error for debugging res.status(500).json({ message: "Error updating profile" }); } }; // Create User exports.createUser = async (req, res) => { - try { - const { name, email, password } = req.body; - - const existingUser = await User.findOne({ email }); - if (existingUser) { - return res.status(400).json({ message: 'An account with this email already exists' }); - } - - const hashedPassword = await bcrypt.hash(password, 10); - let lastUser = await User.find().sort({ userId: -1 }).limit(1); - let newUserId = lastUser.length > 0 ? lastUser[0].userId + 1 : 1; - - const newUser = new User({ - userId: newUserId, - name, - email, - passwordHashed: hashedPassword, - }); - - await newUser.save(); - res.status(201).json({ message: 'User created successfully!' }); - } catch (error) { - res.status(500).json({ message: 'Error creating user' }); - } + try { + const { name, email, password } = req.body; + + const existingUser = await User.findOne({ email: email }); + if (existingUser) { + return res.status(400).json({ message: 'Error: An account with this email already exists' }); + } + + const saltRounds = 10; + const hashedPassword = await bcrypt.hash(password, saltRounds); + + // Autogenerate user ID based on maximum ID in users table + let lastUser = await User.find().sort({"userId": -1}).limit(1) + let newUserId = lastUser[0].userId + 1 + + const newUser = new User({ + userId: newUserId, + name: name, + email: email, + passwordHashed: hashedPassword + }) + await newUser.save(); + res.status(201).json({ message: 'User created successfully!' }); + + } catch (error) { + res.status(500).json({ message: 'Error creating user' }); + } }; // User login exports.loginUser = async (req, res) => { - try { - const { email, password } = req.body; - - const user = await User.findOne({ email }); - if (!user) { - return res.status(401).json({ message: 'Invalid email or password.' }); - } - - const isPasswordValid = await bcrypt.compare(password, user.passwordHashed); - if (!isPasswordValid) { - return res.status(401).json({ message: 'Invalid email or password.' }); - } - - const secretKey = process.env.SECRET_KEY; - if (!secretKey) { - return res.status(500).json({ message: 'Internal server error' }); - } - - const token = jwt.sign({ userId: user.userId, email: user.email }, secretKey, { expiresIn: '1h' }); - res.json({ token, message: 'Login successful' }); - } catch (error) { - res.status(500).json({ message: 'Internal server error' }); - } + try { + const { email, password } = req.body; + + // Find the user by email + const user = await User.findOne({ email: email }); + + if (!user) { + // User not found + return res.status(401).json({ message: 'Invalid email or password.' }); + } + + // Compare the provided password with the stored hashed password + const isPasswordValid = await bcrypt.compare(password, user.passwordHashed); + // console.log('Password validation result:', isPasswordValid); + + if (!isPasswordValid) { + // Password does not match + return res.status(401).json({ message: 'Invalid email or password.' }); + } + + // Generate a token (e.g., JWT) + const secretKey = process.env.SECRET_KEY; // Use environment variable in production + // console.log('JWT_SECRET:', secretKey); + // const secretKey = "myproductionsecret" + + if (!secretKey) { + // console.error('JWT_SECRET is not defined'); + return res.status(500).json({ message: 'no secret key' }); + } + + const token = jwt.sign( + { userId: user.userId, email: user.email }, + secretKey, + { expiresIn: '1h' } + ); + // console.log('JWT Secret:', process.env.SECRET_KEY); + + // Send the token to the client + res.json({ token: token, message: 'Login successful' }); + + } catch (error) { + res.status(500).json({ message: 'Internal Server Error' }); + } }; \ No newline at end of file diff --git a/code/server/db.js b/code/server/db.js deleted file mode 100644 index 54cf3678e..000000000 --- a/code/server/db.js +++ /dev/null @@ -1,93 +0,0 @@ -//This file is for defining the schema and retrieving data -//May turn this into two files moving forward (schema for one file, connection for another) - -const mongoose = require('mongoose') -const dotenv = require('dotenv'); -const path = require('path') - -// Determine the correct .env file based on the environment -const envFile = process.env.NODE_ENV === 'production' ? '.env.production' : '.env.development'; - -// Load the appropriate .env file -// dotenv.config({ path: `../${envFile}` }); -dotenv.config({ path: path.resolve(__dirname, `../${envFile}`) }) - - -let connection = null -let userModel = null -let models = null - - -let Schema = mongoose.Schema - -mongoose.Promise = global.Promise; - -let progressSchema = new Schema({ - date: { type: Date, required: true }, - value: { type: Number, required: true } -}); - -let goalSchema = new Schema({ - goalId: { type: Number, required: true }, - type: { type: String, required: true }, - targetValue: { type: Number, required: true }, - unit: { type: String, required: true }, - createdAt: { type: Date, default: Date.now }, - progress: {type: [progressSchema], default: [] } -}, { - collection: 'goals' -}) - -let userSchema = new Schema({ - userId: { type: Number, required: true }, - email: { type: String, required: true }, - passwordHashed: { type: String, required: true }, - name: { type: String, required: true }, - gender: { type: String, default: "na" }, - dob: { - year: { type: Number, default: 1900, min: 1900, max: 2024 }, - month: { type: Number, default: 1, min: 1, max: 12 }, - day: { type: Number, default: 1, min: 1, max: 31 }, - }, - height: { - feet: { type: Number, default: 0, min: 0, max: 7 }, - inches: { type: Number, default: 0, min: 0, max: 12 } - }, - createdAt: { type: Date, default: Date.now }, - goals: {type: [goalSchema], default: [] } -}, { - collection: 'users' -}) - -let dailyEntrySchema = new Schema({ - dailyEntryId: { type: Number, required: true }, - userId: { type: Number, required: true }, - entryDate: { type: Date }, - weight: { type: Number }, - steps: { type: Number }, - sleep: { type: Number }, - water: { type: Number }, - exercise: { type: Number } -}, { - collection: 'daily_entries' -}) - -module.exports = { - getModel: () => { - if (connection == null) { - connection = mongoose.createConnection(process.env.MONGO_URI) - console.log("Connected to MongoDB!") - userModel = connection.model("User", userSchema); - goalModel = connection.model("Goal", goalSchema); - dailyEntryModel = connection.model("DailyEntry", dailyEntrySchema); - models = {userModel: userModel, goalModel: goalModel, dailyEntryModel: dailyEntryModel} - } - return models - }, - closeConnection: () => { - if (connection != null) { - connection.close() - console.log("MongoDB connection is closed") - } - } -} diff --git a/code/server/models/DailyEntry.js b/code/server/models/DailyEntry.js index e69de29bb..9f396a1e3 100644 --- a/code/server/models/DailyEntry.js +++ b/code/server/models/DailyEntry.js @@ -0,0 +1,17 @@ +const mongoose = require('mongoose'); +const Schema = mongoose.Schema; + +const dailyEntrySchema = new Schema({ + dailyEntryId: { type: Number, required: true }, + userId: { type: Number, required: true }, + entryDate: { type: Date, default: Date.now }, + weight: { type: Number }, + steps: { type: Number }, + sleep: { type: Number }, + water: { type: Number }, + exercise: { type: Number }, +}, { + collection: 'daily_entries', +}); + +module.exports = mongoose.model('DailyEntry', dailyEntrySchema); diff --git a/code/server/server.js b/code/server/server.js index b8b8066e1..7b87025dc 100644 --- a/code/server/server.js +++ b/code/server/server.js @@ -1,16 +1,8 @@ const express = require('express'); - const cors = require('cors'); const connectDB = require('./config/db'); // Assuming you have a separate db connection file const app = express(); -const port = process.env.PORT || 5000 -const User = db.getModel().userModel -const Goal = db.getModel().goalModel -const DailyEntry = db.getModel().dailyEntryModel - -const bcrypt = require('bcrypt'); -const jwt = require('jsonwebtoken'); const port = process.env.PORT || 5000; app.use(cors()); @@ -18,231 +10,6 @@ app.use(express.json()); require('dotenv').config(); -// WILL IMPLEMENT EXPRESS ROUTER--JUST USING THESE ROUTES FOR TESTING - -app.get('/', (req, res) => { - res.send('Server is running...'); -}); - -app.get('/check-connection', async (req, res) => { - res.sendStatus(200) -}) - -app.get('/view-users', async (req, res) => { - const allUsers = await User.find({}) - res.json(allUsers) -}) - -app.get('/manage-profile', async (req, res) => { - try { - // TO DO: UPDATE THIS TO GRAB USER ID FROM LOCAL STORAGE, rather than hardcode - const userId = 10001 // req.userId; - const userProfile = await User.findOne({ userId }); - if (!userProfile) { - return res.status(404).json({ error: "User not found" }); - } - res.json(userProfile); - } catch (error) { - res.status(500).json({ error: "Server error" }); - } -}); - -app.post('/manage-profile', async (req, res) => { - try { - const { userId, name, gender, dob, height } = req.body; - - // Find user in the database using userId - const userProfile = await User.findOne({ userId }); - - // Check if user exists - if (!userProfile) { - return res.status(404).json({ error: "User not found" }); - } - - // Update the profile with the new values - userProfile.name = name; - userProfile.gender = gender; - userProfile.dob = dob; - userProfile.height = height; - - // Save the updated user profile - await userProfile.save(); - - // Send a success response - res.status(200).json({ message: "Profile updated successfully", userProfile }); - } catch (error) { - console.error(error); // Log the error for debugging - res.status(500).json({ message: "Error updating profile" }); - } -}); - -app.post('/create-user', async (req, res) => { - - try { - const { name, email, password } = req.body; - - const existingUser = await User.findOne({ email: email }); - if (existingUser) { - return res.status(400).json({ message: 'Error: An account with this email already exists' }); - } - - const saltRounds = 10; - const hashedPassword = await bcrypt.hash(password, saltRounds); - - // Autogenerate user ID based on maximum ID in users table - let lastUser = await User.find().sort({"userId": -1}).limit(1) - let newUserId = lastUser[0].userId + 1 - - const newUser = new User({ - userId: newUserId, - name: name, - email: email, - passwordHashed: hashedPassword - }) - await newUser.save(); - res.status(201).json({ message: 'User created successfully!' }); - - } catch (error) { - res.status(500).json({ message: 'Error creating user' }); - } - -}) - - -app.post('/login', async (req, res) => { - try { - const { email, password } = req.body; - - // Find the user by email - const user = await User.findOne({ email: email }); - - if (!user) { - // User not found - return res.status(401).json({ message: 'Invalid email or password.' }); - } - - // Compare the provided password with the stored hashed password - const isPasswordValid = await bcrypt.compare(password, user.passwordHashed); - // console.log('Password validation result:', isPasswordValid); - - if (!isPasswordValid) { - // Password does not match - return res.status(401).json({ message: 'Invalid email or password.' }); - } - - // Generate a token (e.g., JWT) - const secretKey = process.env.SECRET_KEY; // Use environment variable in production - // console.log('JWT_SECRET:', secretKey); - // const secretKey = "myproductionsecret" - - if (!secretKey) { - // console.error('JWT_SECRET is not defined'); - return res.status(500).json({ message: 'no secret key' }); - } - - const token = jwt.sign( - { userId: user.userId, email: user.email }, - secretKey, - { expiresIn: '1h' } - ); - // console.log('JWT Secret:', process.env.SECRET_KEY); - - // Send the token to the client - res.json({ token: token, message: 'Login successful' }); - - } catch (error) { - res.status(500).json({ message: 'Internal Server Error' }); - } -}); - - -app.post('/create-goal', async (req, res) => { - try { - // generate new ID based on max goal ID - let lastGoal = await Goal.find().sort({"goalId": -1}).limit(1) - let newGoalId = lastGoal[0].goalId + 1 - - // define unit based on this pre-defined list - let unit; - switch (req.body.type) { - case "sleep": - unit = "hours"; - break; - case "weight": - unit = "lbs"; - break; - case "steps": - unit = "steps"; - break; - case "water": - unit = "glasses"; - break; - case "exercise": - unit = "minutes"; - break; - default: - unit = "unknown"; // default case - } - - // create new goal and save to DB - let newGoal = new Goal({ - goalId: newGoalId, - type: req.body.type, - targetValue: req.body.targetValue, - unit: unit, - // createdAt and progress will use defaults - }) - await newGoal.save() - - // Send a response back to the client indicating success - res.status(201).json({ - message: 'New goal created successfully', - goalId: newGoalId, - }); - - } catch (error) { - console.log(error) - // Send an error response back to the client - res.status(500).json({ error: 'Failed to create goal' }); - } -}) - - -app.post('/enter-daily-data', async (req, res) => { - - try { - const { weight, steps, sleep, water, exercise } = req.body; - - // generate new ID based on max goal ID - let lastEntry = await DailyEntry.find().sort({"dailyEntryId": -1}).limit(1) - let newEntryId = lastEntry[0].dailyEntryId + 1 - - const newDailyEntry = new DailyEntry({ - dailyEntryId: newEntryId, - userId: 10001, // UPDATE TO USERID BASED ON WHO IS LOGGED IN - entryDate: "2024-10-04", // TO DO: FIGURE OUT HOW TO GRAB THIS FROM FORM - weight: weight, - steps: steps, - sleep: sleep, - water: water, - exercise: exercise - }) - - await newDailyEntry.save(); - res.status(201).json({ message: 'Daily entry created successfully!' }); - - } catch (error) { - res.status(500).json({ message: 'Error creating daily entry' }); - } - -}) - - -//Listen for incoming connections -app.listen(port, () => { - console.log(`Server running on port ${port}`); -}); - // Connect to MongoDB connectDB();