diff --git a/backend/src/app.ts b/backend/src/app.ts index ee7e657..87d04a0 100644 --- a/backend/src/app.ts +++ b/backend/src/app.ts @@ -8,6 +8,7 @@ import userRoutes from "./routes/user.routes"; // Consolidated Imports import productRoutes from "./routes/product.routes"; +import cartRoutes from "./routes/cartRoutes"; import mongoose from "mongoose"; import bcrypt from "bcryptjs"; import cookieParser from "cookie-parser"; @@ -127,6 +128,7 @@ app.get("/protected", authenticate, (req: AuthRequest, res: Response) => { app.use('/api/health', healthRoutes); app.use("/api/products", productRoutes); app.use("/api/users", userRoutes); +app.use("/api/cart", cartRoutes); // Default app.get("/", (_req, res) => { diff --git a/backend/src/controllers/cart.controller.ts b/backend/src/controllers/cart.controller.ts new file mode 100644 index 0000000..ec959a6 --- /dev/null +++ b/backend/src/controllers/cart.controller.ts @@ -0,0 +1,151 @@ +import { Request, Response } from "express"; +import mongoose from "mongoose"; +import Cart, { CartItemInput } from "../models/cart.model"; + + +export const addItem = async (req:Request, res:Response): Promise => { + const userId = req.user?.id; + if (!userId) { + res.status(401).json({ message: "Unauthorized"}); return; + } + const {productId, name, price, quantity} = req.body as { + productId: string; + name: string; + price: number; + quantity: number; + }; + + try { + let cart = await Cart.findOne({ userId }); + if (!cart) cart = new Cart({ userId, items: [], totalPrice: 0 }); + const existingItem = cart.items.find(i => i.productId.toString() === productId); +if (existingItem) { + existingItem.quantity += quantity; + } else { + const newItem: CartItemInput = { + productId: new mongoose.Types.ObjectId(productId), + name, + price, + quantity, + }; + cart.items.push(newItem as any); + } +cart.totalPrice = cart.items.reduce((sum, i) => sum + i.price * i.quantity, 0); + await cart.save(); + res.status(200).json(cart); + } catch (err) { + console.error("Add item error:", err); + res.status(500).json({ message: "Server error" }); + } +}; +export const removeItem = async (req: Request, res: Response): Promise => { + const userId = req.user?.id; + if (!userId) { + res.status(401).json({ message: "Unauthorized" }); + return; + } + const { itemId } = req.params; + try { + const cart = await Cart.findOne({ userId }); + if (!cart) { + res.status(404).json({ message: "Cart not found" }); + return; + } + const itemIndex = cart.items.findIndex(i => (i as any)._id?.toString() === itemId); + if (itemIndex===-1) { + res.status(404).json({ message: "Item not found" }); + return; + } + const item = cart.items[itemIndex]; + cart.totalPrice -= item.price * item.quantity; + cart.items.splice(itemIndex, 1); + await cart.save(); + + res.status(200).json(cart); + } catch (err) { + console.error("Remove item error:", err); + res.status(500).json({ message: "Server error" }); + } +}; +export const updateQuantity = async (req: Request, res: Response): Promise => { + const userId = req.user?.id; + if (!userId) { + res.status(401).json({ message: "Unauthorized" }); + return; + } + const { itemId } = req.params; + const { quantity } = req.body as { quantity: number }; + try { + const cart = await Cart.findOne({ userId }); + if (!cart) { + res.status(404).json({ message: "Cart not found" }); + return; + } + const item = cart.items.find(i => (i as any)._id?.toString() === itemId); + if (!item) { + res.status(404).json({ message: "Item not found" }); + return; + } + item.quantity = quantity; + cart.totalPrice = cart.items.reduce( + (sum, i) => sum + i.price * i.quantity, + 0 + ); + + await cart.save(); + res.status(200).json(cart); + } catch (err) { + console.error("Update quantity error:", err); + res.status(500).json({ message: "Server error" }); + } + } + export const getCart = async (req: Request, res: Response): Promise => { + const userId = req.user?.id; + if (!userId) { + res.status(401).json({ message: "Unauthorized" }); + return; + } + +try { + const cart = await Cart.findOne({ userId }).populate("items.productId"); + res.status(200).json(cart || { items: [], totalPrice: 0 }); + } catch (err) { + console.error("Get cart error:", err); + res.status(500).json({ message: "Server error" }); + } +}; + +export const checkout = async (req: Request, res: Response): Promise => { + const userId = req.user?.id; + if (!userId) { + res.status(401).json({ message: "Unauthorized" }); + return; + } + + try { + const cart = await Cart.findOne({ userId }); + + if (!cart || cart.items.length === 0) { + res.status(400).json({ message: "Cart is empty" }); + return; + } + + const orderData = { + userId: new mongoose.Types.ObjectId(userId), + items: cart.items, + total: cart.totalPrice, + date: new Date(), + }; + + //Create order database and here push the orderData in it. + + cart.items = []; + cart.totalPrice = 0; + await cart.save(); + + res.status(200).json({ message: "Checkout successful" }); + } catch (err) { + console.error("Checkout error:", err); + res.status(500).json({ message: "Server error" }); + } +}; diff --git a/backend/src/models/cart.model.ts b/backend/src/models/cart.model.ts new file mode 100644 index 0000000..971e990 --- /dev/null +++ b/backend/src/models/cart.model.ts @@ -0,0 +1,38 @@ +import mongoose, { Schema, Types } from "mongoose"; + +export interface ICartItem { + _id?: Types.ObjectId; + productId: Types.ObjectId; + name: string; + price: number; + quantity: number; +} + +export type CartItemInput = Omit; + +export interface ICart extends mongoose.Document { + userId: Types.ObjectId; + items: ICartItem[]; + totalPrice: number; +} + +const cartItemSchema = new Schema( + { + productId: { type: Schema.Types.ObjectId, ref: "Product", required: true }, + name: { type: String, required: true }, + price: { type: Number, required: true }, + quantity: { type: Number, default: 1, min: 1 }, + }, + { _id: true } +); + +const cartSchema = new Schema( + { + userId: { type: Schema.Types.ObjectId, ref: "User", required: true }, + items: [cartItemSchema], + totalPrice: { type: Number, default: 0 }, + }, + { timestamps: true } +); + +export default mongoose.model("Cart", cartSchema); diff --git a/backend/src/routes/cartRoutes.ts b/backend/src/routes/cartRoutes.ts new file mode 100644 index 0000000..ee7a344 --- /dev/null +++ b/backend/src/routes/cartRoutes.ts @@ -0,0 +1,18 @@ +import express, { Router } from "express"; +import { + addItem, + updateQuantity, + removeItem, + getCart, + checkout, +} from "../controllers/cart.controller"; + +const router: Router = express.Router(); + +router.post("/", addItem); +router.patch("/:itemId", updateQuantity); +router.delete("/:itemId", removeItem); +router.get("/", getCart); +router.post("/checkout", checkout); + +export default router; diff --git a/backend/src/types.d.ts b/backend/src/types.d.ts index ee0fbd1..5d111cf 100644 --- a/backend/src/types.d.ts +++ b/backend/src/types.d.ts @@ -1,5 +1,5 @@ declare namespace Express { export interface Request { - user?: { sub: string; username: string; role: string }; + user?: { id: string; username: string; role: string }; } -} +} \ No newline at end of file