webupdate
This commit is contained in:
377
backend/routes/customer-cart.js
Normal file
377
backend/routes/customer-cart.js
Normal file
@@ -0,0 +1,377 @@
|
||||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const { pool } = require("../config/database");
|
||||
const logger = require("../config/logger");
|
||||
|
||||
// Middleware to check customer auth from session
|
||||
const requireCustomerAuth = (req, res, next) => {
|
||||
if (!req.session || !req.session.customerId) {
|
||||
return res
|
||||
.status(401)
|
||||
.json({ success: false, message: "Please login to continue" });
|
||||
}
|
||||
next();
|
||||
};
|
||||
|
||||
// ===========================
|
||||
// CART ROUTES
|
||||
// ===========================
|
||||
|
||||
// Get cart items
|
||||
router.get("/cart", requireCustomerAuth, async (req, res) => {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
`SELECT cc.id, cc.product_id, cc.quantity, cc.variant_color, cc.variant_size, cc.added_at,
|
||||
p.name, p.price, p.imageurl, p.slug
|
||||
FROM customer_cart cc
|
||||
JOIN products p ON p.id = cc.product_id
|
||||
WHERE cc.customer_id = $1
|
||||
ORDER BY cc.added_at DESC`,
|
||||
[req.session.customerId]
|
||||
);
|
||||
|
||||
const items = result.rows.map((row) => ({
|
||||
id: row.id,
|
||||
productId: row.product_id,
|
||||
name: row.name,
|
||||
price: parseFloat(row.price),
|
||||
image: row.imageurl,
|
||||
slug: row.slug,
|
||||
quantity: row.quantity,
|
||||
variantColor: row.variant_color,
|
||||
variantSize: row.variant_size,
|
||||
addedAt: row.added_at,
|
||||
}));
|
||||
|
||||
const total = items.reduce(
|
||||
(sum, item) => sum + item.price * item.quantity,
|
||||
0
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
items,
|
||||
itemCount: items.length,
|
||||
total: total.toFixed(2),
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error("Get cart error:", error);
|
||||
res.status(500).json({ success: false, message: "Failed to get cart" });
|
||||
}
|
||||
});
|
||||
|
||||
// Add to cart
|
||||
router.post("/cart", requireCustomerAuth, async (req, res) => {
|
||||
try {
|
||||
const { productId, quantity = 1, variantColor, variantSize } = req.body;
|
||||
|
||||
if (!productId) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ success: false, message: "Product ID is required" });
|
||||
}
|
||||
|
||||
// Check if product exists
|
||||
const productCheck = await pool.query(
|
||||
"SELECT id, name FROM products WHERE id = $1",
|
||||
[productId]
|
||||
);
|
||||
if (productCheck.rows.length === 0) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ success: false, message: "Product not found" });
|
||||
}
|
||||
|
||||
// Insert or update cart item
|
||||
const result = await pool.query(
|
||||
`INSERT INTO customer_cart (customer_id, product_id, quantity, variant_color, variant_size)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
ON CONFLICT (customer_id, product_id, variant_color, variant_size)
|
||||
DO UPDATE SET quantity = customer_cart.quantity + EXCLUDED.quantity, updated_at = CURRENT_TIMESTAMP
|
||||
RETURNING id`,
|
||||
[
|
||||
req.session.customerId,
|
||||
productId,
|
||||
quantity,
|
||||
variantColor || null,
|
||||
variantSize || null,
|
||||
]
|
||||
);
|
||||
|
||||
logger.info(
|
||||
`Cart item added for customer ${req.session.customerId}: ${productId}`
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: "Added to cart",
|
||||
cartItemId: result.rows[0].id,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error("Add to cart error:", error);
|
||||
res.status(500).json({ success: false, message: "Failed to add to cart" });
|
||||
}
|
||||
});
|
||||
|
||||
// Update cart quantity
|
||||
router.put("/cart/:id", requireCustomerAuth, async (req, res) => {
|
||||
try {
|
||||
const { quantity } = req.body;
|
||||
|
||||
if (!quantity || quantity < 1) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ success: false, message: "Quantity must be at least 1" });
|
||||
}
|
||||
|
||||
const result = await pool.query(
|
||||
`UPDATE customer_cart SET quantity = $1, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $2 AND customer_id = $3
|
||||
RETURNING id`,
|
||||
[quantity, req.params.id, req.session.customerId]
|
||||
);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ success: false, message: "Cart item not found" });
|
||||
}
|
||||
|
||||
res.json({ success: true, message: "Cart updated" });
|
||||
} catch (error) {
|
||||
logger.error("Update cart error:", error);
|
||||
res.status(500).json({ success: false, message: "Failed to update cart" });
|
||||
}
|
||||
});
|
||||
|
||||
// Remove from cart
|
||||
router.delete("/cart/:id", requireCustomerAuth, async (req, res) => {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
"DELETE FROM customer_cart WHERE id = $1 AND customer_id = $2 RETURNING id",
|
||||
[req.params.id, req.session.customerId]
|
||||
);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ success: false, message: "Cart item not found" });
|
||||
}
|
||||
|
||||
res.json({ success: true, message: "Removed from cart" });
|
||||
} catch (error) {
|
||||
logger.error("Remove from cart error:", error);
|
||||
res
|
||||
.status(500)
|
||||
.json({ success: false, message: "Failed to remove from cart" });
|
||||
}
|
||||
});
|
||||
|
||||
// Clear cart
|
||||
router.delete("/cart", requireCustomerAuth, async (req, res) => {
|
||||
try {
|
||||
await pool.query("DELETE FROM customer_cart WHERE customer_id = $1", [
|
||||
req.session.customerId,
|
||||
]);
|
||||
res.json({ success: true, message: "Cart cleared" });
|
||||
} catch (error) {
|
||||
logger.error("Clear cart error:", error);
|
||||
res.status(500).json({ success: false, message: "Failed to clear cart" });
|
||||
}
|
||||
});
|
||||
|
||||
// ===========================
|
||||
// WISHLIST ROUTES
|
||||
// ===========================
|
||||
|
||||
// Get wishlist items
|
||||
router.get("/wishlist", requireCustomerAuth, async (req, res) => {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
`SELECT cw.id, cw.product_id, cw.added_at,
|
||||
p.name, p.price, p.imageurl, p.slug
|
||||
FROM customer_wishlist cw
|
||||
JOIN products p ON p.id = cw.product_id
|
||||
WHERE cw.customer_id = $1
|
||||
ORDER BY cw.added_at DESC`,
|
||||
[req.session.customerId]
|
||||
);
|
||||
|
||||
const items = result.rows.map((row) => ({
|
||||
id: row.id,
|
||||
productId: row.product_id,
|
||||
name: row.name,
|
||||
price: parseFloat(row.price),
|
||||
image: row.imageurl,
|
||||
slug: row.slug,
|
||||
addedAt: row.added_at,
|
||||
}));
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
items,
|
||||
itemCount: items.length,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error("Get wishlist error:", error);
|
||||
res.status(500).json({ success: false, message: "Failed to get wishlist" });
|
||||
}
|
||||
});
|
||||
|
||||
// Add to wishlist
|
||||
router.post("/wishlist", requireCustomerAuth, async (req, res) => {
|
||||
try {
|
||||
const { productId } = req.body;
|
||||
|
||||
if (!productId) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ success: false, message: "Product ID is required" });
|
||||
}
|
||||
|
||||
// Check if product exists
|
||||
const productCheck = await pool.query(
|
||||
"SELECT id, name FROM products WHERE id = $1",
|
||||
[productId]
|
||||
);
|
||||
if (productCheck.rows.length === 0) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ success: false, message: "Product not found" });
|
||||
}
|
||||
|
||||
// Insert wishlist item (ignore if already exists)
|
||||
await pool.query(
|
||||
`INSERT INTO customer_wishlist (customer_id, product_id)
|
||||
VALUES ($1, $2)
|
||||
ON CONFLICT (customer_id, product_id) DO NOTHING`,
|
||||
[req.session.customerId, productId]
|
||||
);
|
||||
|
||||
logger.info(
|
||||
`Wishlist item added for customer ${req.session.customerId}: ${productId}`
|
||||
);
|
||||
|
||||
res.json({ success: true, message: "Added to wishlist" });
|
||||
} catch (error) {
|
||||
logger.error("Add to wishlist error:", error);
|
||||
res
|
||||
.status(500)
|
||||
.json({ success: false, message: "Failed to add to wishlist" });
|
||||
}
|
||||
});
|
||||
|
||||
// Remove from wishlist
|
||||
router.delete("/wishlist/:id", requireCustomerAuth, async (req, res) => {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
"DELETE FROM customer_wishlist WHERE id = $1 AND customer_id = $2 RETURNING id",
|
||||
[req.params.id, req.session.customerId]
|
||||
);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ success: false, message: "Wishlist item not found" });
|
||||
}
|
||||
|
||||
res.json({ success: true, message: "Removed from wishlist" });
|
||||
} catch (error) {
|
||||
logger.error("Remove from wishlist error:", error);
|
||||
res
|
||||
.status(500)
|
||||
.json({ success: false, message: "Failed to remove from wishlist" });
|
||||
}
|
||||
});
|
||||
|
||||
// Remove from wishlist by product ID
|
||||
router.delete(
|
||||
"/wishlist/product/:productId",
|
||||
requireCustomerAuth,
|
||||
async (req, res) => {
|
||||
try {
|
||||
await pool.query(
|
||||
"DELETE FROM customer_wishlist WHERE product_id = $1 AND customer_id = $2",
|
||||
[req.params.productId, req.session.customerId]
|
||||
);
|
||||
|
||||
res.json({ success: true, message: "Removed from wishlist" });
|
||||
} catch (error) {
|
||||
logger.error("Remove from wishlist error:", error);
|
||||
res
|
||||
.status(500)
|
||||
.json({ success: false, message: "Failed to remove from wishlist" });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Check if product is in wishlist
|
||||
router.get(
|
||||
"/wishlist/check/:productId",
|
||||
requireCustomerAuth,
|
||||
async (req, res) => {
|
||||
try {
|
||||
const result = await pool.query(
|
||||
"SELECT id FROM customer_wishlist WHERE product_id = $1 AND customer_id = $2",
|
||||
[req.params.productId, req.session.customerId]
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
inWishlist: result.rows.length > 0,
|
||||
wishlistItemId: result.rows[0]?.id || null,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error("Check wishlist error:", error);
|
||||
res
|
||||
.status(500)
|
||||
.json({ success: false, message: "Failed to check wishlist" });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Get cart count (for navbar badge)
|
||||
router.get("/cart/count", async (req, res) => {
|
||||
try {
|
||||
if (!req.session || !req.session.customerId) {
|
||||
return res.json({ success: true, count: 0 });
|
||||
}
|
||||
|
||||
const result = await pool.query(
|
||||
"SELECT COALESCE(SUM(quantity), 0) as count FROM customer_cart WHERE customer_id = $1",
|
||||
[req.session.customerId]
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
count: parseInt(result.rows[0].count),
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error("Get cart count error:", error);
|
||||
res.json({ success: true, count: 0 });
|
||||
}
|
||||
});
|
||||
|
||||
// Get wishlist count (for navbar badge)
|
||||
router.get("/wishlist/count", async (req, res) => {
|
||||
try {
|
||||
if (!req.session || !req.session.customerId) {
|
||||
return res.json({ success: true, count: 0 });
|
||||
}
|
||||
|
||||
const result = await pool.query(
|
||||
"SELECT COUNT(*) as count FROM customer_wishlist WHERE customer_id = $1",
|
||||
[req.session.customerId]
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
count: parseInt(result.rows[0].count),
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error("Get wishlist count error:", error);
|
||||
res.json({ success: true, count: 0 });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user