-
Notifications
You must be signed in to change notification settings - Fork 167
FE+BE product list #159
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
lesavantdon
wants to merge
16
commits into
projectshft:master
Choose a base branch
from
lesavantdon:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
FE+BE product list #159
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
7e700e0
Add code to FE+BE.productlist directory
54333a0
first draft
5ee469e
Update project structure, remove submodule, and re-add files
768722e
reupload
61149ed
change
6e82ac5
final draft
37717de
update readme
c9db76a
final final
36a1c9c
re-hashed final
79ef0fd
updated code
6937e00
final draft w/ git ignore
6c09cb2
final
ab1fd0a
finally
88f9afd
removed node_modules and package-lock.json
lesavantdon ce38f5f
finalized
lesavantdon ad551ff
errors fixed, reported BE
lesavantdon File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Binary file not shown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| PORT=8000 | ||
| MONGODB_URI=mongodb://lesavantdon:icecream2@localhost:27017/productsdb?authSource=admin | ||
|
|
||
| console.log('MongoDB URI:', process.env.MONGODB_URI); // Debugging line | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| # Node modules | ||
| node_modules/ | ||
| package-lock.json/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| *dependencies required for back end* | ||
| "cors": "^2.8.5", | ||
| "dotenv": "^16.4.5", | ||
| "express": "^4.19.2", | ||
| "mongoose": "^8.5.3" | ||
|
|
||
| *from terminal CD into BE* | ||
|
|
||
| CD BE "npm start" to run back end | ||
| make sure data is seeded into the mongo database with | ||
| "BE git:(master) ✗ node scripts/seed.js" in shell/terminal |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| const express = require('express'); | ||
| const router = express.Router(); | ||
| const productController = require('../../controllers/productController'); | ||
|
|
||
|
|
||
| router.get('/', productController.getAllProducts); | ||
| router.get('/:id', productController.getProductById); | ||
| router.post('/', productController.createProduct); | ||
| router.put('/:id', productController.updateProduct); | ||
| router.delete('/:id', productController.deleteProduct); | ||
|
|
||
| module.exports = router; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| const express = require('express'); | ||
| const router = express.Router(); | ||
| const reviewController = require('../../controllers/reviewController'); // Make sure the path is correct | ||
|
|
||
|
|
||
| // In your reviews route file (e.g., api/reviews/index.js) | ||
|
|
||
| router.get('/', reviewController.getAllReviews); | ||
| router.post('/:productId', reviewController.createReview); // Create a new review | ||
| router.get('/:productId', reviewController.getReviewsByProductId); | ||
| router.get('/reviews/:productId', reviewController.getPaginatedReviewsByProductId); | ||
|
|
||
| router.delete('/:reviewId', reviewController.deleteReview); | ||
|
|
||
|
|
||
| module.exports = router; | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| // app.js | ||
| const express = require('express'); | ||
| const dotenv = require('dotenv'); | ||
| const cors = require('cors'); // Import cors | ||
| const connectDB = require('./config/db'); | ||
| const productsRoutes = require('./api/products/index.js'); | ||
| const reviewsRoutes = require('./api/reviews/index.js'); // Import reviews routes | ||
| const errorHandler = require('./middleware/errorHandler'); | ||
|
|
||
| dotenv.config(); // Load environment variables from .env file | ||
| const app = express(); | ||
| app.use(cors()); | ||
|
|
||
| app.use(express.json()); | ||
| app.use((req, res, next) => { | ||
| res.header("Access-Control-Allow-Origin", "*"); | ||
| res.header("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE"); | ||
| res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); | ||
| next(); | ||
| }); | ||
|
|
||
| app.get('/', (req, res) => { | ||
| res.send('Welcome to the API'); | ||
| }); | ||
|
|
||
| app.use('/api/products', productsRoutes); | ||
| app.use('/api/reviews', reviewsRoutes); | ||
|
|
||
|
|
||
| app.use((req, res) => { | ||
| res.status(404).send('Sorry, that route doesn’t exist.'); | ||
| }); | ||
| app.use((err, req, res, next) => { | ||
| console.error(err.stack); | ||
| res.status(500).send('Something broke!'); | ||
| }); | ||
|
|
||
| module.exports = app; // Export the app |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| const mongoose = require('mongoose'); | ||
|
|
||
| const connectDB = async () => { | ||
| try { | ||
| const conn = await mongoose.connect(process.env.MONGODB_URI, { | ||
| // The following options are deprecated and can be removed: | ||
| // useNewUrlParser: true, | ||
| // useUnifiedTopology: true, | ||
| }); | ||
|
|
||
| console.log(`MongoDB Connected: ${conn.connection.host}`); | ||
| } catch (error) { | ||
| console.error(`Error: ${error.message}`); | ||
| process.exit(1); // Exit process with failure | ||
| } | ||
| }; | ||
|
|
||
| module.exports = connectDB; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,132 @@ | ||||||||||
| const Product = require('../models/product'); | ||||||||||
|
|
||||||||||
| // Get all products with pagination, filtering, and sorting | ||||||||||
| const getAllProducts = async (req, res) => { | ||||||||||
| const { page = 1, limit = 9, category = 'all', sort = 'asc' } = req.query; | ||||||||||
|
|
||||||||||
| const query = {}; | ||||||||||
| // Filter by category if not 'all' | ||||||||||
| if (category && category !== 'all') { | ||||||||||
| query.category = category; | ||||||||||
| } | ||||||||||
|
Comment on lines
+9
to
+11
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
|
|
||||||||||
| try { | ||||||||||
| // Get total count of products for pagination | ||||||||||
| const totalProducts = await Product.countDocuments(query); | ||||||||||
|
|
||||||||||
| // Calculate the number of products to skip | ||||||||||
| const skip = (page - 1) * limit; | ||||||||||
|
|
||||||||||
| // Fetch the products from the database | ||||||||||
| const products = await Product.find(query) | ||||||||||
| .sort({ price: sort === 'asc' ? 1 : -1 }) // Sort by price | ||||||||||
| .skip(skip) // Skip the appropriate number of products | ||||||||||
| .limit(parseInt(limit)); // Limit the number of results | ||||||||||
|
|
||||||||||
| // Calculate total pages | ||||||||||
| const totalPages = Math.ceil(totalProducts / limit); | ||||||||||
|
|
||||||||||
| // Send the response | ||||||||||
| res.json({ | ||||||||||
| products, | ||||||||||
| totalPages | ||||||||||
| }); | ||||||||||
| } catch (error) { | ||||||||||
| console.error(error); | ||||||||||
| res.status(500).json({ message: 'Error fetching products.' }); | ||||||||||
| } | ||||||||||
| }; | ||||||||||
|
|
||||||||||
|
|
||||||||||
| // Get a single product by ID | ||||||||||
| const getProductById = async (req, res) => { | ||||||||||
| const { id } = req.params; | ||||||||||
|
|
||||||||||
| try { | ||||||||||
| const product = await Product.findById(id); | ||||||||||
|
|
||||||||||
| if (!product) { | ||||||||||
| return res.status(404).json({ message: 'Product not found.' }); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| res.json(product); | ||||||||||
| } catch (error) { | ||||||||||
| console.error(error); | ||||||||||
| res.status(500).json({ message: 'Error fetching product.' }); | ||||||||||
| } | ||||||||||
| }; | ||||||||||
|
|
||||||||||
| // Create a new product | ||||||||||
| const createProduct = async (req, res) => { | ||||||||||
| const { userName, name, description, price, category, image } = req.body; | ||||||||||
|
|
||||||||||
| if (!userName || !name || !description || !price || !category || !image) { | ||||||||||
| return res.status(400).json({ message: 'All fields are required.' }); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| try { | ||||||||||
| const newProduct = new Product({ | ||||||||||
| userName, | ||||||||||
| name, | ||||||||||
| description, | ||||||||||
| price, | ||||||||||
| category, | ||||||||||
| image | ||||||||||
| }); | ||||||||||
|
|
||||||||||
| const savedProduct = await newProduct.save(); | ||||||||||
| res.status(201).json(savedProduct); | ||||||||||
| } catch (error) { | ||||||||||
| console.error(error); | ||||||||||
| res.status(500).json({ message: 'Error creating product.' }); | ||||||||||
| } | ||||||||||
| }; | ||||||||||
|
|
||||||||||
| // Update a product by ID | ||||||||||
| const updateProduct = async (req, res) => { | ||||||||||
| const { id } = req.params; | ||||||||||
| const { userName, name, description, price, category, image } = req.body; | ||||||||||
|
|
||||||||||
| try { | ||||||||||
| const updatedProduct = await Product.findByIdAndUpdate( | ||||||||||
| id, | ||||||||||
| { userName, name, description, price, category, image }, | ||||||||||
| { new: true, runValidators: true } | ||||||||||
| ); | ||||||||||
|
|
||||||||||
| if (!updatedProduct) { | ||||||||||
| return res.status(404).json({ message: 'Product not found.' }); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| res.json(updatedProduct); | ||||||||||
| } catch (error) { | ||||||||||
| console.error(error); | ||||||||||
| res.status(500).json({ message: 'Error updating product.' }); | ||||||||||
| } | ||||||||||
| }; | ||||||||||
|
|
||||||||||
| // Delete a product by ID | ||||||||||
| const deleteProduct = async (req, res) => { | ||||||||||
| const { id } = req.params; | ||||||||||
|
|
||||||||||
| try { | ||||||||||
| const deletedProduct = await Product.findByIdAndDelete(id); | ||||||||||
|
|
||||||||||
| if (!deletedProduct) { | ||||||||||
| return res.status(404).json({ message: 'Product not found.' }); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| res.status(200).json({ message: 'Product deleted successfully.' }); | ||||||||||
| } catch (error) { | ||||||||||
| console.error(error); | ||||||||||
| res.status(500).json({ message: 'Error deleting product.' }); | ||||||||||
| } | ||||||||||
| }; | ||||||||||
|
|
||||||||||
| module.exports = { | ||||||||||
| getAllProducts, | ||||||||||
| getProductById, | ||||||||||
| createProduct, | ||||||||||
| updateProduct, | ||||||||||
| deleteProduct | ||||||||||
| }; | ||||||||||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| const Review = require('../models/review'); | ||
| const Product = require('../models/product'); | ||
| const mongoose = require('mongoose'); | ||
|
|
||
| const getAllReviews = async (req, res) => { | ||
| try { | ||
| const reviews = await Review.find(); // Fetch all reviews | ||
| res.json(reviews); // Return the reviews | ||
| } catch (error) { | ||
| console.error('Error fetching reviews:', error); | ||
| res.status(500).json({ message: 'Server error' }); | ||
| } | ||
| }; | ||
|
|
||
| const createReview = async (req, res) => { | ||
| try { | ||
| // Extract data from request body | ||
| const { user, rating, review, productId } = req.body; | ||
|
|
||
| // Create a new review instance | ||
| const newReview = new Review({ | ||
| user, | ||
| rating, | ||
| review, | ||
| productId | ||
| }); | ||
|
|
||
| // Save the review to the database | ||
| const savedReview = await newReview.save(); | ||
|
|
||
| // Send the saved review as a response | ||
| return res.status(201).json(savedReview); | ||
| } catch (error) { | ||
| console.error('Error creating review:', error); | ||
| return res.status(500).json({ message: 'Failed to create review.' }); | ||
| } | ||
| }; | ||
|
|
||
| // Corrected the function declaration | ||
| const getReviewsByProductId = async (req, res) => { | ||
| try { | ||
| const { productId } = req.params; // Get the product ID from the route | ||
| const reviews = await Review.find({ productId }); // Find reviews associated with the product ID | ||
|
|
||
| if (!reviews || reviews.length === 0) { | ||
| return res.status(404).json({ message: 'No reviews found for this product.' }); | ||
| } | ||
|
|
||
| res.json(reviews); // Return the found reviews | ||
| } catch (error) { | ||
| console.error('Error fetching reviews:', error); | ||
| res.status(500).json({ message: 'Server error' }); | ||
| } | ||
| }; | ||
|
|
||
|
|
||
|
|
||
| // Delete a review by productId and reviewId | ||
| const deleteReview = async (req, res) => { | ||
| try { | ||
| const { reviewId } = req.params; // Get reviewId from request parameters | ||
| console.log('Attempting to delete review with ID:', reviewId); | ||
|
|
||
| const review = await Review.findById(reviewId); // Check if review exists | ||
| if (!review) { | ||
| console.error('Review not found:', reviewId); | ||
| return res.status(404).json({ message: 'Review not found' }); | ||
| } | ||
|
|
||
| await Review.findByIdAndDelete(reviewId); // Delete the review | ||
| console.log('Review deleted successfully:', reviewId); | ||
|
|
||
| return res.status(200).json({ message: 'Review deleted successfully' }); | ||
| } catch (error) { | ||
| console.error('Error deleting review:', error); | ||
| return res.status(500).json({ message: 'Server error', error }); | ||
| } | ||
| }; | ||
|
|
||
| // Fetch reviews for a product with pagination | ||
| const getPaginatedReviewsByProductId = async (req, res) => { | ||
| const { productId } = req.params; | ||
| const { page = 1, limit = 4 } = req.query; // Default to page 1 and limit 4 reviews | ||
|
|
||
| try { | ||
| // Fetch reviews using pagination | ||
| const reviews = await Review.find({ productId }) | ||
| .limit(limit * 1) // Limit to the specified number of reviews | ||
| .skip((page - 1) * limit) // Skip to the relevant page | ||
| .exec(); | ||
|
|
||
| // Get the total number of reviews | ||
| const totalReviews = await Review.countDocuments({ productId }); | ||
|
|
||
| res.status(200).json({ | ||
| reviews, | ||
| totalPages: Math.ceil(totalReviews / limit), | ||
| currentPage: page, | ||
| }); | ||
| } catch (error) { | ||
| res.status(500).json({ message: 'Error fetching paginated reviews', error }); | ||
| } | ||
| }; | ||
|
|
||
|
|
||
|
|
||
|
|
||
| module.exports = { | ||
| getAllReviews, | ||
| createReview, | ||
| getReviewsByProductId, | ||
| deleteReview, | ||
| getPaginatedReviewsByProductId, | ||
|
|
||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| const errorHandler = (err, req, res, next) => { | ||
| const statusCode = res.statusCode === 200 ? 500 : res.statusCode; | ||
| res.status(statusCode); | ||
| res.json({ | ||
| message: err.message, | ||
| stack: process.env.NODE_ENV === 'production' ? null : err.stack, | ||
| }); | ||
| }; | ||
|
|
||
| module.exports = errorHandler; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| const mongoose = require('mongoose'); | ||
|
|
||
| // Product Schema | ||
| const productSchema = new mongoose.Schema({ | ||
| userName: { type: String, required: true }, | ||
| name: { type: String, required: true }, | ||
| description: { type: String, required: true }, | ||
| price: { type: Number, required: true }, | ||
| category: { type: String, required: true }, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ideally we would want to limit categories and use an enum or some specific ones |
||
| image: { type: String, required: true }, | ||
| }, { timestamps: true }); | ||
|
|
||
| const Product = mongoose.model('Product', productSchema); | ||
|
|
||
| module.exports = Product; | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
very clear and good organization