You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

424 lines
11 KiB
JavaScript

const User = require("../models/User.js");
const Product = require("../models/Product.js");
const Order = require("../models/Order.js");
const auth = require("../auth.js");
const {verify, verifyAdmin} = auth;
const multer = require('multer');
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'public/images/');
},
filename: (req, file, cb) => {
cb(null, file.fieldname + "-" + Date.now() + "-" + file.originalname);
},
});
const upload = multer({ storage: storage });
// Controllers
// create product controller
module.exports.createProduct = async (req, res) => {
try {
const { name, price, description, inventory } = req.body;
// console.log(req.file)
// Create a new product instance
const product = new Product({
name,
price,
description,
inventory,
image: (req.file != undefined) ? {
imageName: req.file.originalname,
}
:
null
});
// Save the product to the database
await product.save();
res.status(201).json(true);
} catch (error) {
console.error(error);
res.status(500).json(false);
}
};
// Middleware to handle image upload
module.exports.uploadImage = upload.single('image');
module.exports.isProductExisting = async (req, res) => {
try {
const { productName } = req.body;
const existingProduct = await Product.findOne({ name: productName });
const productExists = !!existingProduct;
if (productExists == true) {
res.json(true);
} else {
res.json(false);
}
} catch (error) {
console.error(error);
res.status(500).json(false);
}
};
// retrieve all products controller
module.exports.getAllProducts = async (req, res) => {
try {
// Fetch all products from the database
const products = await Product.find();
res.json(products);
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Error retrieving products' });
}
};
// retrieve all active products controller
exports.getAllActiveProducts = async (req, res) => {
try {
const products = await Product.find({ isActive: true });
res.json(products);
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Error retrieving active products' });
}
};
// search products controller
exports.searchProducts = async (req, res) => {
try {
const { productName } = req.body;
const products = await Product.find({
name: { $regex: new RegExp(productName, 'i') },
isActive: true
});
res.json({products});
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Error searching products' });
}
};
// Helper function to escape special characters in the search query
function escapeRegex(text) {
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
}
// update product controller
exports.updateProduct = async (req, res) => {
try {
const { productId } = req.params;
const { name, price, description, inventory } = req.body;
// Find the product to update
const product = await Product.findByIdAndUpdate(productId, {
name,
price,
description,
inventory,
// image,
}, { new: true });
if (!product) {
return res.status(404).json(false);
}
res.json(true);
} catch (error) {
console.error(error);
res.status(500).json(false);
}
};
// archive product controller
exports.archiveProduct = async (req, res) => {
try {
const { productId } = req.params;
// Find the product to archive
const product = await Product.findById(productId);
if (!product) {
return res.status(404).json({ message: 'Product not found' });
}else if (product.isActive === false){
return res.status(404).json({ message: 'Product already archived' });
}
product.isActive = false;
await product.save();
res.json({ message: 'Product archived successfully' });
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Error archiving product' });
}
};
// activate product controller
exports.activateProduct = async (req, res) => {
try {
const { productId } = req.params;
// Find the product to archive
const product = await Product.findById(productId);
if (!product) {
return res.status(404).json({ message: 'Product not found' });
}else if (product.isActive === true){
return res.status(404).json({ message: 'Product already active' });
}
product.isActive = true;
await product.save();
res.json({ message: 'Product activated successfully' });
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Error activating product' });
}
};
// Controller to create an order || check-out
exports.createOrder = async (req, res, next) => {
try {
let cartItems = req.body.orderedItems;
// Fetch product prices from the database
await Product.find({ _id: { $in: cartItems.map(item => item.productId) } }).then( result => {
for (i = 0 ; i < result.length; i++) {
cartItems[i].price = result[i].price;
}
});
// Create the order with retrieved prices
const newOrder = new Order({
userId: req.user.id,
products: cartItems,
totalAmount: calculateTotalPrice(cartItems)
});
// Save the order and update inventory
await newOrder.save();
await updateProductInventory(cartItems);
// Update User orders
await User.findById(req.user.id).then( result => {
const newOrderUserUpdate = {
products: cartItems,
totalAmount: calculateTotalPrice(cartItems),
purchasedOn : new Date()
}
result.orders.push(newOrderUserUpdate);
result.save();
})
res.status(201).json({ message: 'Order created successfully', newOrder });
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Error creating order' });
}
};
// Helper functions for calculating total price and updating inventory
function calculateTotalPrice(cartItems) {
return cartItems.reduce((total, item) => {
const itemPrice = Number(item.price); // Ensure price is a number
const itemQuantity = Number(item.quantity); // Ensure quantity is a number
return total + (itemPrice * itemQuantity);
}, 0);
}
async function updateProductInventory(cartItems) {
try {
await Promise.all(
cartItems.map(async item => {
const product = await Product.findById(item.productId);
if (!product) {
throw new Error(`Product not found: ${item.productId}`);
}
// Ensure quantity doesn't go below zero
const newQuantity = Math.max(0, product.inventory - item.quantity);
product.inventory = newQuantity;
await product.save();
})
);
} catch (error) {
console.error('Error updating product quantities:', error);
// Handle the error appropriately (e.g., rollback order creation)
}
}
// My Cart
exports.addProductToCart = async (req, res) => {
try {
const { productId, quantity } = req.body;
// Find the user
const user = await User.findById(req.user.id);
// Check if the cart array exists
if (!user.myCart) {
user.myCart = [];
}
const existingItemIndex = user.myCart.findIndex(item => item.productId === productId);
if (existingItemIndex !== -1) {
// Update quantity of existing item
user.myCart[existingItemIndex].quantity += quantity;
} else {
if (quantity <= 0) {
return res.json({ message: 'Provide valid quantity' });
}
// Add new item to cart
const product = await Product.findById(productId);
user.myCart.push({
productId,
name: product.name,
quantity
});
}
await user.save(); // Save the updated user with cart items
res.json({ message: 'Product added to cart successfully' });
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Error adding product to cart' });
}
};
exports.updateProductQuantity = async (req, res) => {
try {
const { productId, quantity } = req.body;
// Find the user
const user = await User.findById(req.user.id);
if (!user.myCart) {
return res.status(400).json({ message: 'Cart is empty' });
}
const itemIndex = user.myCart.findIndex(item => item.productId === productId);
if (itemIndex === -1) {
return res.status(404).json({ message: 'Product not found in cart' });
}
// Validate quantity (e.g., must be positive, not exceed available inventory)
if (quantity <= 0) {
return res.status(400).json({ message: 'Quantity must be greater than zero' });
}
// Update quantity in the cart
user.myCart[itemIndex].quantity = quantity;
await user.save(); // Save the updated cart
res.json({ message: 'Product quantity updated successfully' });
console.log(user.myCart);
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Error updating product quantity' });
}
};
exports.removeProductFromCart = async (req, res) => {
try {
const productId = req.params.productId;
const user = await User.findById(req.user.id);
const existingItemIndex = user.myCart.findIndex(item => item.productId === productId);
let x = await User.findByIdAndUpdate(
req.user.id,
{
$pull: { myCart: { productId } }
},
{ new: true } // Return the updated user document
).exec();
if (existingItemIndex <= 0) {
res.json({ message: 'Product not in cart' });
}else{
res.json({ message: 'Product removed from cart successfully' });
}
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Error removing product from cart' });
}
};
exports.getCartDetails = async (req, res) => {
try {
const user = await User.findById(req.user.id);
if (!user || !user.myCart || user.myCart.length < 0) {
return res.json({ cartItems: [], totalPrice: 0 }); // Handle empty cart
}
const cartItems = user.myCart;
let totalPrice = 0;
for (const item of cartItems) {
const findItemPrice = await Product.findById(item.productId);
const subtotal = findItemPrice.price * item.quantity;
totalPrice += subtotal;
item.price = findItemPrice.price;
// Add subtotal to the item object for clarity in response
item.subtotal = subtotal;
}
res.json({ cartItems, totalPrice });
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Error fetching cart details' });
}
};
module.exports.getProduct = (request, response) => {
let reqParams = request.params.productId;
Product.findById(reqParams).then(result => response.send(result))
.catch(error => response.send(error));
}