From 2ad72ac34b12c8361ac96cc8413e73f1e3c368fa Mon Sep 17 00:00:00 2001 From: VaishnaviP-06 Date: Thu, 18 Jun 2026 22:46:25 +0530 Subject: [PATCH] chore: remove eslint warnings and cleanup unused variables --- BACKEND/controllers/product.controller.js | 53 +++++++++++-------- BACKEND/middleware/authMiddleware.js | 6 +-- BACKEND/middleware/errorMiddleware.js | 18 +++---- FRONTEND/src/components/ui/ProductCard.jsx | 27 ++++------ FRONTEND/src/components/ui/ProductReviews.jsx | 14 +++-- 5 files changed, 58 insertions(+), 60 deletions(-) diff --git a/BACKEND/controllers/product.controller.js b/BACKEND/controllers/product.controller.js index 187cb28..7862154 100644 --- a/BACKEND/controllers/product.controller.js +++ b/BACKEND/controllers/product.controller.js @@ -96,7 +96,6 @@ export const getProducts = async (req, res, next) => { if (maxPrice) filter.price.$lte = Number(maxPrice); } if (brand) { - // Case-insensitive brand search filter.brand = { $regex: new RegExp(brand, 'i') }; } if (minRating) { @@ -158,6 +157,7 @@ export const createProduct = async (req, res, next) => { } let finalImageUrl = imageUrl || ''; + let cloudinaryPublicId; // track uploaded image's public ID for potential cleanup if (req.file) { if (!cloudinaryConfigured()) { @@ -166,7 +166,8 @@ export const createProduct = async (req, res, next) => { try { const result = await uploadToCloudinary(req.file.buffer); finalImageUrl = result.secure_url; - } catch (error) { + cloudinaryPublicId = result.public_id; // save public ID for cleanup if needed + } catch (_error) { return next(new AppError("Image upload failed", 500)); } } @@ -194,7 +195,15 @@ export const createProduct = async (req, res, next) => { await invalidateProductCache(); res.status(201).json({ success: true, data: newProduct }); } catch (error) { - next(error); + // CLEANUP: delete uploaded Cloudinary image if save failed + if (cloudinaryPublicId) { + try { + await cloudinary.uploader.destroy(cloudinaryPublicId); + } catch (destroyError) { + console.error("Failed to delete Cloudinary image:", destroyError.message); + } + } + return next(error); } }; @@ -245,8 +254,7 @@ export const updateProduct = async (req, res, next) => { try { const result = await uploadToCloudinary(req.file.buffer); updateData.image = result.secure_url; - - } catch (error) { + } catch (_error) { return next(new AppError("Image upload failed", 500)); } } @@ -256,13 +264,13 @@ export const updateProduct = async (req, res, next) => { if (!updatedProduct) { return next(new AppError("Product not found", 404)); } - if (req.file){ + if (req.file) { const oldPublicId = extractCloudinaryPublicId(existing.image); - if (oldPublicId) { - cloudinary.uploader.destroy(oldPublicId).catch((err) => { - console.warn("Old image cleanup failed:", err.message); - }); - } + if (oldPublicId) { + cloudinary.uploader.destroy(oldPublicId).catch((err) => { + console.warn("Old image cleanup failed:", err.message); + }); + } } await indexProduct(updatedProduct); @@ -305,20 +313,19 @@ export const deleteProduct = async (req, res, next) => { const { id } = req.params; if (!mongoose.Types.ObjectId.isValid(id)) { - return res.status(404).json({ success: false, message: "Invalid Product Id" }); + return next(new AppError("Invalid Product Id format", 404)); } try { const product = await Product.findByIdAndUpdate(id, { isDeleted: true }, { new: true }); if (!product) { - return res.status(404).json({ success: false, message: "Product not found" }); + return next(new AppError("Product not found", 404)); } await deleteProductFromIndex(id); await invalidateProductCache(); res.status(200).json({ success: true, message: "Product deleted successfully" }); } catch (error) { - console.log("error in deleting product:", error.message); - res.status(500).json({ success: false, message: "Server Error" }); + next(error); } }; @@ -371,7 +378,7 @@ export const getRelatedProducts = async (req, res) => { const orConditions = []; if (product.category) orConditions.push({ category: product.category }); if (product.brand) orConditions.push({ brand: product.brand }); - if (targetTagsSet.size > 0) orConditions.push({ tags: { $in: [ ...targetTagsSet ] } }); + if (targetTagsSet.size > 0) orConditions.push({ tags: { $in: [...targetTagsSet] } }); const query = { _id: { $ne: product._id }, @@ -396,7 +403,7 @@ export const getRelatedProducts = async (req, res) => { if (c.tags && c.tags.length > 0) { for (const tag of c.tags) { - if (targetTags.has(tag.toLowerCase())) { + if (targetTagsSet.has(tag.toLowerCase())) { score += 2; } } @@ -441,11 +448,15 @@ export const getProductBundle = async (req, res) => { .slice(0, 3); const bundleTotal = [product, ...items.map(i => i.product)] - .reduce((sum, p) => sum + p.price, 0); + .reduce((sum, p) => sum + (Number(p?.price) || 0), 0); const bundleDiscount = 0.1; - const bundlePrice = +(bundleTotal * (1 - bundleDiscount)).toFixed(2); - const savings = +(bundleTotal * bundleDiscount).toFixed(2); + const bundlePrice = bundleTotal > 0 + ? +(bundleTotal * (1 - bundleDiscount)).toFixed(2) + : 0; + const savings = bundleTotal > 0 + ? +(bundleTotal * bundleDiscount).toFixed(2) + : 0; res.status(200).json({ success: true, @@ -476,13 +487,11 @@ export const searchProducts = async (req, res, next) => { } try { - // Try Elasticsearch first const esProducts = await searchProductsES(q); if (esProducts) { return res.status(200).json({ success: true, data: esProducts }); } - // Fallback to MongoDB regex search const safeQuery = escapeRegex(q); const regex = new RegExp(safeQuery, 'i'); const products = await Product.find({ name: regex, isDeleted: { $ne: true } }); diff --git a/BACKEND/middleware/authMiddleware.js b/BACKEND/middleware/authMiddleware.js index 2d19fdc..f878425 100644 --- a/BACKEND/middleware/authMiddleware.js +++ b/BACKEND/middleware/authMiddleware.js @@ -14,7 +14,6 @@ const authMiddleware = async (req, res, next) => { const token = authHeader.split(" ")[1]; - // JWT specific errors alag handle honge let decoded; try { decoded = jwt.verify(token, process.env.JWT_SECRET); @@ -32,7 +31,6 @@ const authMiddleware = async (req, res, next) => { }); } - // Validate decoded payload before DB lookup if (!decoded?.id) { return res.status(401).json({ success: false, @@ -40,7 +38,6 @@ const authMiddleware = async (req, res, next) => { }); } - // User existence verify karo DB se const user = await User.findById(decoded.id).select("-password"); if (!user) { @@ -59,7 +56,7 @@ const authMiddleware = async (req, res, next) => { }; next(); - } catch (error) { + } catch (_error) { return res.status(500).json({ success: false, message: "Internal server error during authentication.", @@ -68,4 +65,3 @@ const authMiddleware = async (req, res, next) => { }; export default authMiddleware; - diff --git a/BACKEND/middleware/errorMiddleware.js b/BACKEND/middleware/errorMiddleware.js index ad5c866..d71aa3f 100644 --- a/BACKEND/middleware/errorMiddleware.js +++ b/BACKEND/middleware/errorMiddleware.js @@ -1,4 +1,3 @@ -// Custom Error Class (for different error types) export class AppError extends Error { constructor(message, statusCode) { super(message); @@ -7,45 +6,42 @@ export class AppError extends Error { } } -// ADD THIS - 404 Handler for unknown API routes export const notFoundHandler = (req, res, next) => { - // Check if it's an API route (starts with /api) if (req.path.startsWith('/api')) { return res.status(404).json({ success: false, message: `API route not found: ${req.method} ${req.path}` }); } - // For non-API routes, pass to next middleware (like frontend) + next(); }; -// Global Error Handler Middleware -export const errorHandler = (err, req, res, next) => { - // Default values + +export const errorHandler = (err, req, res, _next) => { let statusCode = err.statusCode || 500; let message = err.message || "Internal Server Error"; - // Handle Mongoose Validation Errors (e.g., min:0, required, etc.) + if (err.name === 'ValidationError') { statusCode = 400; message = Object.values(err.errors).map(e => e.message).join(', '); } - // Handle Duplicate Key Error (MongoDB - when unique field repeats) + if (err.code === 11000) { statusCode = 400; const field = Object.keys(err.keyPattern)[0]; message = `Duplicate field value: ${field}. Please use another value.`; } - // Handle Cast Error (Invalid ObjectId format) + if (err.name === 'CastError') { statusCode = 400; message = `Invalid ${err.path}: ${err.value}`; } - // Send Response + res.status(statusCode).json({ success: false, message: message, diff --git a/FRONTEND/src/components/ui/ProductCard.jsx b/FRONTEND/src/components/ui/ProductCard.jsx index 3000265..a3a5846 100644 --- a/FRONTEND/src/components/ui/ProductCard.jsx +++ b/FRONTEND/src/components/ui/ProductCard.jsx @@ -48,9 +48,9 @@ const ProductCard = ({ product }) => { const [isInWishlist, setIsInWishlist] = useState(false); const handleClose = () => { - setUpdatedProduct(product); - setImagePreview(product.image); - onClose(); + setUpdatedProduct(product); + setImagePreview(product.image); + onClose(); }; const fileInputRef = useRef(null); @@ -73,7 +73,6 @@ const ProductCard = ({ product }) => { const isInCompare = compareList.some((p) => p._id === product._id); const { addToCart } = useCart(); - const { currency, rates } = useCurrencyStore(); const { addToWishlist, removeFromWishlist, checkInWishlist } = useWishlist(); const toast = useToast(); @@ -96,11 +95,8 @@ const ProductCard = ({ product }) => { // Check wishlist status on mount useEffect(() => { - const checkWishlist = async () => { - const inWishlist = await checkInWishlist(product._id); - setIsInWishlist(inWishlist); - }; - checkWishlist(); + const inWishlist = checkInWishlist(product._id); + setIsInWishlist(inWishlist); }, [product._id, checkInWishlist]); // Revoke blob URLs to avoid memory leaks @@ -266,7 +262,7 @@ const ProductCard = ({ product }) => { {/* Price */} - {formatPrice(product.price, currency, rates)} + ${product.price} {/* Tags */} @@ -363,7 +359,7 @@ const ProductCard = ({ product }) => { - {/* ── Delete Confirmation Dialog ── */} + {/* Delete Confirmation Dialog */} { - {/* ── Edit / Update Modal ── */} + {/*Edit / Update Modal*/} @@ -620,10 +616,7 @@ const ProductCard = ({ product }) => { > Update - @@ -633,4 +626,4 @@ const ProductCard = ({ product }) => { ); }; -export default ProductCard; \ No newline at end of file +export default ProductCard; diff --git a/FRONTEND/src/components/ui/ProductReviews.jsx b/FRONTEND/src/components/ui/ProductReviews.jsx index 87f9e10..d3eaaaf 100644 --- a/FRONTEND/src/components/ui/ProductReviews.jsx +++ b/FRONTEND/src/components/ui/ProductReviews.jsx @@ -67,11 +67,15 @@ const RatingSummary = ({ reviews, filterStar, onFilterChange, distribution, aver const rounded = averageRating ?? Math.round((reviews.reduce((sum, r) => sum + r.rating, 0) / totalCount) * 10) / 10; - const dist = distribution || [5, 4, 3, 2, 1].map((star) => ({ - star, - count: reviews.filter((r) => r.rating === star).length, - })); - + const dist = distribution + ? [5, 4, 3, 2, 1].map((star) => ({ + star, + count: distribution[star] ?? 0, + })) + : [5, 4, 3, 2, 1].map((star) => ({ + star, + count: reviews.filter((r) => r.rating === star).length, + })); return (