Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions backend/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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) => {
Expand Down
151 changes: 151 additions & 0 deletions backend/src/controllers/cart.controller.ts
Original file line number Diff line number Diff line change
@@ -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<void> => {
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<void> => {
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<void> => {
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<void> => {
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<void> => {
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" });
}
};
38 changes: 38 additions & 0 deletions backend/src/models/cart.model.ts
Original file line number Diff line number Diff line change
@@ -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<ICartItem, "_id">;

export interface ICart extends mongoose.Document {
userId: Types.ObjectId;
items: ICartItem[];
totalPrice: number;
}

const cartItemSchema = new Schema<ICartItem>(
{
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<ICart>(
{
userId: { type: Schema.Types.ObjectId, ref: "User", required: true },
items: [cartItemSchema],
totalPrice: { type: Number, default: 0 },
},
{ timestamps: true }
);

export default mongoose.model<ICart>("Cart", cartSchema);
18 changes: 18 additions & 0 deletions backend/src/routes/cartRoutes.ts
Original file line number Diff line number Diff line change
@@ -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;
4 changes: 2 additions & 2 deletions backend/src/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
declare namespace Express {
export interface Request {
user?: { sub: string; username: string; role: string };
user?: { id: string; username: string; role: string };
}
}
}
Loading