Files
SkyArtShop/backend/routes/customer-cart.js

378 lines
10 KiB
JavaScript
Raw Normal View History

2026-01-18 02:22:05 -06:00
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;