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' }); } }; // getting product name by id exports.getProductName = async (req, res) => { try { const { productId } = req.body; // Find the product by productId const product = await Product.findOne({ _id: productId }).select('name'); if (!product) { return res.status(404).json({ error: 'Product not found' }); } // Send the product name in the response res.json(product); } catch (error) { console.error('Error getting product name:', error); res.status(500).json({ error: 'Internal Server Error' }); } }; // 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(true); } catch (error) { console.error(error); res.status(500).json(false); } }; // 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 = []; } // Check if the product already exists in the cart const existingItemIndex = user.myCart.findIndex(item => item.productId === productId); if (existingItemIndex !== -1) { // Update quantity of existing item await User.findByIdAndUpdate( req.user.id, { $inc: { [`myCart.${existingItemIndex}.quantity`]: quantity } // Increment the quantity field }, { new: true } // Return the updated user after the operation ); } 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)); }