Compare commits
No commits in common. '9e665f8710599849458beb738c56a4ff30d404d0' and 'f190090be164a24362fea323091128126de50b6a' have entirely different histories.
9e665f8710
...
f190090be1
7 changed files with 93 additions and 219 deletions
@ -1,62 +0,0 @@ |
|||||||
'use strict'; |
|
||||||
|
|
||||||
module.exports = { |
|
||||||
up: async (queryInterface, Sequelize) => { |
|
||||||
await queryInterface.createTable('Carts', { |
|
||||||
id: { |
|
||||||
type: Sequelize.INTEGER, |
|
||||||
allowNull: false, |
|
||||||
autoIncrement: true, |
|
||||||
primaryKey: true, |
|
||||||
}, |
|
||||||
userId: { |
|
||||||
type: Sequelize.INTEGER, |
|
||||||
allowNull: false, |
|
||||||
references: { |
|
||||||
model: 'Users', |
|
||||||
key: 'id', |
|
||||||
}, |
|
||||||
onDelete: 'CASCADE', |
|
||||||
}, |
|
||||||
productId: { |
|
||||||
type: Sequelize.INTEGER, |
|
||||||
allowNull: false, |
|
||||||
references: { |
|
||||||
model: 'Products',
|
|
||||||
key: 'id', |
|
||||||
}, |
|
||||||
onDelete: 'CASCADE', |
|
||||||
}, |
|
||||||
quantity: { |
|
||||||
type: Sequelize.INTEGER, |
|
||||||
allowNull: false, |
|
||||||
}, |
|
||||||
productPrice: { |
|
||||||
type: Sequelize.DECIMAL(10, 2), |
|
||||||
allowNull: false, |
|
||||||
}, |
|
||||||
totalPrice: { |
|
||||||
type: Sequelize.DECIMAL(10, 2), |
|
||||||
allowNull: false, |
|
||||||
}, |
|
||||||
productName: { |
|
||||||
type: Sequelize.STRING, |
|
||||||
allowNull: false, |
|
||||||
}, |
|
||||||
createdAt: { |
|
||||||
type: Sequelize.DATE, |
|
||||||
allowNull: false, |
|
||||||
defaultValue: Sequelize.NOW, |
|
||||||
}, |
|
||||||
updatedAt: { |
|
||||||
type: Sequelize.DATE, |
|
||||||
allowNull: false, |
|
||||||
defaultValue: Sequelize.NOW, |
|
||||||
}, |
|
||||||
}); |
|
||||||
}, |
|
||||||
|
|
||||||
down: async (queryInterface, Sequelize) => { |
|
||||||
await queryInterface.dropTable('Carts'); |
|
||||||
}, |
|
||||||
}; |
|
@ -1,46 +1,26 @@ |
|||||||
import { Controller, Get, Post, Patch, Delete, Body, Param, UseGuards, Request } from "@nestjs/common"; |
import { Controller, Get, Post, Body, Patch, Param, Delete } from "@nestjs/common"; |
||||||
import { CartService } from "./cart.service"; |
import { CartService } from "./cart.service"; |
||||||
import { JwtAuthGuard } from "src/guard/auth.guard"; |
|
||||||
import { AddToCartDto } from "./dto/add-to-cart.dto"; |
|
||||||
import { UpdateCartDto } from "./dto/update-cart.dto"; |
|
||||||
import { Cart } from "./entities/cart.entity"; |
import { Cart } from "./entities/cart.entity"; |
||||||
|
|
||||||
@Controller("cart") |
@Controller("cart") |
||||||
export class CartController { |
export class CartController { |
||||||
constructor(private readonly cartService: CartService) {} |
constructor(private readonly cartService: CartService) {} |
||||||
|
|
||||||
@UseGuards(JwtAuthGuard) |
|
||||||
@Post() |
@Post() |
||||||
async addToCart(@Body() addToCartDto: AddToCartDto, @Request() req: any): Promise<{ message: string; cartItem: Cart }> { |
async addToCart(@Body() body: { userId: number; productId: number; quantity: number }): Promise<{ message: string; cartItem: Cart }> { |
||||||
const userId = req.user.id; |
const { userId, productId, quantity } = body; |
||||||
return this.cartService.addToCart({ ...addToCartDto, userId }); |
const result = await this.cartService.addToCart(userId, productId, quantity); |
||||||
|
return result; |
||||||
} |
} |
||||||
|
@Get(":userId") |
||||||
@UseGuards(JwtAuthGuard) |
async getUserCart(@Param("userId") userId: number) { |
||||||
@Get() |
|
||||||
async getUserCart(@Request() req: any): Promise<{ cartItems: Cart[]; totalPrice: number }> { |
|
||||||
const userId = req.user.id; |
|
||||||
return this.cartService.getUserCart(userId); |
return this.cartService.getUserCart(userId); |
||||||
} |
} |
||||||
|
|
||||||
@UseGuards(JwtAuthGuard) |
@Delete(":userId/:productId") |
||||||
@Patch(":productId") |
async removeFromCart( |
||||||
async updateCart(@Param("productId") productId: number, @Body() updateCartDto: UpdateCartDto, @Request() req: any): Promise<{ message: string; updatedCart: Cart }> { |
@Param("userId") userId: number, |
||||||
const userId = req.user.id; |
@Param("productId") productId: number,
|
||||||
const updatedCart = await this.cartService.updateCart(userId, productId, updateCartDto.quantity); |
): Promise<{ message: string }> { |
||||||
return { |
return this.cartService.removeFromCart(userId, productId); |
||||||
message: "Cart updated successfully", |
|
||||||
updatedCart, |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
@UseGuards(JwtAuthGuard) |
|
||||||
@Delete(":productId") |
|
||||||
async removeFromCart(@Param("productId") productId: number, @Request() req: any): Promise<{ message: string }> { |
|
||||||
const userId = req.user.id; |
|
||||||
await this.cartService.removeFromCart(userId, productId); |
|
||||||
return { |
|
||||||
message: "Product removed from cart successfully", |
|
||||||
}; |
|
||||||
} |
} |
||||||
} |
} |
||||||
|
@ -1,98 +1,101 @@ |
|||||||
import { Injectable, HttpException, HttpStatus } from "@nestjs/common"; |
import { Injectable } from "@nestjs/common"; |
||||||
import { InjectModel } from "@nestjs/sequelize"; |
import { InjectModel } from "@nestjs/sequelize"; |
||||||
import { Cart } from "./entities/cart.entity"; |
import { Cart } from "./entities/cart.entity"; |
||||||
|
import { HttpException, HttpStatus } from "@nestjs/common"; |
||||||
import { CartResponse } from "./cart.response"; |
import { CartResponse } from "./cart.response"; |
||||||
import { User } from "src/users/entities/user.entity"; |
import { User } from "src/users/entities/user.entity"; |
||||||
import { Product } from "src/products/entities/product.entity"; |
import { Product } from "src/products/entities/product.entity"; |
||||||
import { console } from "inspector"; |
|
||||||
|
|
||||||
@Injectable() |
@Injectable() |
||||||
export class CartService { |
export class CartService { |
||||||
constructor( |
constructor( |
||||||
@InjectModel(Cart) private readonly cartModel: typeof Cart, |
@InjectModel(Cart) private readonly cartModel: typeof Cart, |
||||||
|
@InjectModel(User) private readonly userModel: typeof User, |
||||||
@InjectModel(Product) private readonly productModel: typeof Product, |
@InjectModel(Product) private readonly productModel: typeof Product, |
||||||
) {} |
) {} |
||||||
|
|
||||||
// Add product to cart
|
|
||||||
async addToCart(addToCartDto: { userId: number; productId: number; quantity: number }): Promise<{ message: string; cartItem: Cart }> { |
|
||||||
const { userId, productId, quantity } = addToCartDto; |
|
||||||
|
|
||||||
if (!userId || !productId || !quantity) { |
|
||||||
throw new HttpException("Missing required parameters: userId, productId, and quantity are required.", HttpStatus.BAD_REQUEST); |
|
||||||
} |
|
||||||
|
|
||||||
const product = await this.productModel.findByPk(productId); |
|
||||||
if (!product) { |
|
||||||
throw new HttpException("Product not found!", HttpStatus.NOT_FOUND); |
|
||||||
} |
|
||||||
|
|
||||||
const existingCartItem = await this.cartModel.findOne({ |
|
||||||
where: { userId, productId }, |
|
||||||
}); |
|
||||||
|
|
||||||
if (existingCartItem) { |
async addToCart(userId: number, productId: number, quantity: number): Promise<CartResponse> { |
||||||
existingCartItem.quantity += Number(quantity); |
try { |
||||||
existingCartItem.totalPrice = existingCartItem.quantity * existingCartItem.productPrice; |
if (!userId || !productId || !quantity) { |
||||||
await existingCartItem.save(); |
throw new HttpException("Missing required parameters: userId, productId, and quantity are required.", HttpStatus.BAD_REQUEST); |
||||||
|
} |
||||||
|
|
||||||
|
const user = await this.userModel.findByPk(userId); |
||||||
|
if (!user) { |
||||||
|
throw new HttpException("User not found!", HttpStatus.NOT_FOUND); |
||||||
|
} |
||||||
|
|
||||||
|
const product = await this.productModel.findByPk(productId); |
||||||
|
if (!product) { |
||||||
|
throw new HttpException("Product not found!", HttpStatus.NOT_FOUND); |
||||||
|
} |
||||||
|
|
||||||
|
const existingCartItem = await this.cartModel.findOne({ |
||||||
|
where: { userId, productId }, |
||||||
|
}); |
||||||
|
|
||||||
|
if (existingCartItem) { |
||||||
|
existingCartItem.quantity += Number(quantity); |
||||||
|
await existingCartItem.save(); |
||||||
|
return { |
||||||
|
message: "Product quantity updated in cart successfully!", |
||||||
|
cartItem: existingCartItem, |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
const newCartItem = await this.cartModel.create({ userId, productId, quantity }); |
||||||
|
|
||||||
return { |
return { |
||||||
message: "Product quantity updated in cart successfully!", |
message: "Product added to cart successfully!", |
||||||
cartItem: existingCartItem, |
cartItem: newCartItem, |
||||||
}; |
}; |
||||||
|
} catch (error) { |
||||||
|
// Enhanced error handling
|
||||||
|
if (error instanceof HttpException) { |
||||||
|
throw error; |
||||||
|
} |
||||||
|
throw new HttpException(`An error occurred while adding the product to the cart: ${error.message}`, HttpStatus.INTERNAL_SERVER_ERROR); |
||||||
} |
} |
||||||
|
|
||||||
const newCartItem = await this.cartModel.create({ userId, productId, quantity, productPrice: product.price, totalPrice: product.price * quantity, productName: product.name }); |
|
||||||
|
|
||||||
return { |
|
||||||
message: "Product added to cart successfully!", |
|
||||||
cartItem: newCartItem, |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
// Get user's cart
|
|
||||||
async getUserCart(userId: number): Promise<{ cartItems: Cart[]; totalPrice: number }> { |
|
||||||
const cartItems = await this.cartModel.findAll({ |
|
||||||
where: { userId }, |
|
||||||
include: [ |
|
||||||
{ |
|
||||||
model: Product, |
|
||||||
attributes: ["id", "name", "price", "description", "imageUrl"], |
|
||||||
}, |
|
||||||
], |
|
||||||
}); |
|
||||||
|
|
||||||
if (!cartItems || cartItems.length === 0) { |
|
||||||
throw new HttpException("No cart items found for the specified user.", HttpStatus.NOT_FOUND); |
|
||||||
} |
|
||||||
|
|
||||||
const totalPrice = cartItems.reduce((sum, item) => sum + Number(item.totalPrice), 0); |
|
||||||
|
|
||||||
return { cartItems, totalPrice }; |
|
||||||
} |
} |
||||||
|
async getUserCart(userId: number): Promise<Cart[]> { |
||||||
// Update cart item quantity
|
try { |
||||||
async updateCart(userId: number, productId: number, quantity: number): Promise<Cart> { |
const cartItems = await this.cartModel.findAll({ |
||||||
const cartItem = await this.cartModel.findOne({ where: { userId, productId } }); |
where: { userId }, |
||||||
|
include: ["product"], |
||||||
if (!cartItem) { |
}); |
||||||
throw new HttpException("Product not found in the cart.", HttpStatus.NOT_FOUND); |
if (!cartItems || cartItems.length === 0) { |
||||||
|
throw new HttpException("No cart items found for the specified user.", HttpStatus.NOT_FOUND); |
||||||
|
} |
||||||
|
|
||||||
|
return cartItems; |
||||||
|
} catch (error) { |
||||||
|
if (error instanceof HttpException) { |
||||||
|
throw error; |
||||||
|
} |
||||||
|
|
||||||
|
throw new HttpException("An error occurred while retrieving the cart.", HttpStatus.INTERNAL_SERVER_ERROR); |
||||||
} |
} |
||||||
|
|
||||||
cartItem.quantity = quantity; |
|
||||||
cartItem.totalPrice = cartItem.quantity * cartItem.productPrice; |
|
||||||
await cartItem.save(); |
|
||||||
return cartItem; |
|
||||||
} |
} |
||||||
|
|
||||||
// Remove product from cart
|
|
||||||
async removeFromCart(userId: number, productId: number): Promise<{ message: string }> { |
async removeFromCart(userId: number, productId: number): Promise<{ message: string }> { |
||||||
const cartItem = await this.cartModel.findOne({ where: { userId, productId } }); |
try { |
||||||
|
const cartItem = await this.cartModel.findOne({ where: { userId, productId } }); |
||||||
if (!cartItem) { |
|
||||||
throw new HttpException("Product not found in the cart.", HttpStatus.NOT_FOUND); |
if (!cartItem) { |
||||||
|
throw new HttpException('Product not found in the cart.', HttpStatus.NOT_FOUND); |
||||||
|
} |
||||||
|
|
||||||
|
await cartItem.destroy(); |
||||||
|
return { message: 'Item deleted from your cart successfully.' }; |
||||||
|
} catch (error) { |
||||||
|
if (error instanceof HttpException) { |
||||||
|
throw error; |
||||||
|
} |
||||||
|
|
||||||
|
throw new HttpException( |
||||||
|
'An error occurred while removing the product from the cart.', |
||||||
|
HttpStatus.INTERNAL_SERVER_ERROR, |
||||||
|
); |
||||||
} |
} |
||||||
|
|
||||||
await cartItem.destroy(); |
|
||||||
return { message: "Item deleted from your cart successfully." }; |
|
||||||
} |
} |
||||||
} |
} |
||||||
|
@ -1,13 +0,0 @@ |
|||||||
// add-to-cart.dto.ts
|
|
||||||
import { IsInt, IsNotEmpty, IsNumber, min, Min } from 'class-validator'; |
|
||||||
|
|
||||||
export class AddToCartDto { |
|
||||||
@IsNumber()
|
|
||||||
@IsNotEmpty() |
|
||||||
productId: number; |
|
||||||
|
|
||||||
@IsInt() |
|
||||||
@IsNotEmpty() |
|
||||||
@Min(0) |
|
||||||
quantity: number; |
|
||||||
} |
|
@ -1,8 +0,0 @@ |
|||||||
// update-cart.dto.ts
|
|
||||||
import { IsInt, Min } from 'class-validator'; |
|
||||||
|
|
||||||
export class UpdateCartDto { |
|
||||||
@IsInt() |
|
||||||
@Min(1) |
|
||||||
quantity: number; |
|
||||||
} |
|
Loading…
Reference in new issue