Skip to content

Commit

Permalink
Merge pull request #1319 from Jhaemis-hack/dev
Browse files Browse the repository at this point in the history
"FEAT: Implement Product Review and Star Rating Feature"
  • Loading branch information
incredible-phoenix246 authored Mar 1, 2025
2 parents 187cae5 + 2f5a051 commit 878c9c5
Show file tree
Hide file tree
Showing 15 changed files with 210 additions and 103 deletions.
46 changes: 19 additions & 27 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,41 +1,33 @@
NODE_ENV=development
PROFILE=local
PORT=5000
HOST=
REDIS_PORT= 6379
DB_SSL=true
NODE_ENV=development

PORT=3008

JWT_SECRET=someSecrets
JWT_EXPIRY_TIMEFRAME=3600


REDIS_HOST=localhost
REDIS_PORT=6379
DB_TYPE=

DB_TYPE=postgres
DB_USERNAME=
DB_PASSWORD=
DB_HOST=
DB_NAME=hng
DB_HOST=localhost
DB_DATABASE=
DB_ENTITIES=dist/src/modules/**/entities/**/*.entity{.ts,.js}
DB_MIGRATIONS=dist/db/migrations/*{.ts,.js}
POSGRES_USER=$DB_USERNAME
POST
JWT_SECRET=gsgs
JWT_EXPIRY_TIMEFRAME=1500000
DB_SSL=false
JWT_REFRESH_SECRET=bbp
JWT_REFRESH_EXPIRY_TIMEFRAME=15
GOOGLE_REDIRECT_URI=

JWT_SECRET=someSecrets
JWT_EXPIRY_TIMEFRAME=3600

ADMIN_SECRET_KEY=sometext

GOOGLE_CLIENT_SECRET=
GOOGLE_CLIENT_ID=
OAUTH_LOGIN_REDIRECT=
SMTP_HOST=

SMTP_HOST=sandbox.smtp.mailtrap.io
SMTP_PORT=587
SERVER_NAME=Boilerplate
SERVER_NAME=api
SMTP_USER=
SMTP_PASSWORD=
FRONTEND_URL=
ADMIN_SECRET=
SUPPORT_EMAIL=
AUTH_PASSWORD=
BASE_URL=
FLUTTERWAVE_SECRET_KEY=
FLUTTERWAVE_BASE_URL=
SMTP_PASSWORD=
2 changes: 1 addition & 1 deletion .env.local
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ NODE_ENV=development
PORT=3000

DB_USERNAME=username
DB_PASSWORD=password
DB_PASSWORD=password123
DB_TYPE=postgres
DB_NAME=database
DB_HOST=localhost
Expand Down
12 changes: 4 additions & 8 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -402,12 +402,12 @@ dist

# User specific ignores
todo.txt
/.vscode/
.vscode/

# Docker compose
docker-compose.yml
data/
<<<<<<< HEAD
data/
docker-compose.yml
package-lock.json
Expand All @@ -419,16 +419,12 @@ docker-compose.yml
data/
.dev.env


=======

# Docker compose
docker-compose.yml
data/
>>>>>>> d080450 (chore: created a docker-compose.yml file and updated the gitignore)
/compose/compose.yaml
compose/compose.yaml

data/
docker-compose.yml
package-lock.json/
package-lock.json
.dev.env

Expand Down
65 changes: 0 additions & 65 deletions compose/compose.yaml

This file was deleted.

6 changes: 6 additions & 0 deletions src/modules/products/current-user.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { createParamDecorator, ExecutionContext } from '@nestjs/common';

export const CurrentUser = createParamDecorator((data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.user; // This works if AuthGuard attaches user object to request
});
11 changes: 11 additions & 0 deletions src/modules/products/dto/create-review.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { IsInt, IsString, Max, Min } from 'class-validator';

export class CreateReviewDto {
@IsInt()
@Min(1)
@Max(5)
rating: number;

@IsString()
review: string;
}
20 changes: 20 additions & 0 deletions src/modules/products/dto/product-response.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { ApiProperty } from '@nestjs/swagger';

export class ProductResponseDto {
id: string;
name: string;
description: string;
averageRating: number;
totalReviews: number;

@ApiProperty({ type: () => [ReviewSummaryDto] })
recentReviews: ReviewSummaryDto[];
}

// Define ReviewSummaryDto **inside the same file**, avoiding unnecessary imports
class ReviewSummaryDto {
rating: number;
review: string;
createdBy: string;
createdAt: Date;
}
4 changes: 4 additions & 0 deletions src/modules/products/entities/product.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Comment } from '../../../modules/comments/entities/comments.entity';
import { Organisation } from '../../../modules/organisations/entities/organisations.entity';
import { Cart } from '../../dashboard/entities/cart.entity';
import { OrderItem } from '../../dashboard/entities/order-items.entity';
import { Review } from './review.entity';

export enum StockStatusType {
IN_STOCK = 'in stock',
Expand Down Expand Up @@ -40,6 +41,9 @@ export class Product extends AbstractBaseEntity {
@Column({ type: 'int', nullable: false, default: 0 })
quantity: number;

@OneToMany(() => Review, review => review.product)
reviews: Review[];

@Column({
type: 'enum',
enum: ProductSizeType,
Expand Down
26 changes: 26 additions & 0 deletions src/modules/products/entities/review.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Entity, Column, PrimaryGeneratedColumn, ManyToOne, CreateDateColumn, UpdateDateColumn } from 'typeorm';
import { Product } from './product.entity';

@Entity()
export class Review {
@PrimaryGeneratedColumn('uuid')
id: string;

@Column({ type: 'int', width: 1 })
rating: number;

@Column({ type: 'text' })
review: string;

@Column()
createdBy: string; // This will be user ID

@ManyToOne(() => Product, product => product.reviews, { onDelete: 'CASCADE' })
product: Product;

@CreateDateColumn()
createdAt: Date;

@UpdateDateColumn()
updatedAt: Date;
}
30 changes: 30 additions & 0 deletions src/modules/products/products.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ import { ProductsService } from './products.service';
import { UpdateProductDTO } from './dto/update-product.dto';
import { isUUID } from 'class-validator';
import { GetTotalProductsResponseDto } from './dto/get-total-products.dto';
import { CreateReviewDto } from './dto/create-review.dto';
import { User } from '../user/entities/user.entity';
import { AuthGuard } from '../../guards/auth.guard';
import { CurrentUser } from './current-user.decorator';
import { skipAuth } from '@shared/helpers/skipAuth';
import { OwnershipGuard } from '@guards/authorization.guard';
import { AddCommentDto } from '@modules/comments/dto/add-comment.dto';
Expand Down Expand Up @@ -180,4 +184,30 @@ export class ProductsController {
async getProductStock(@Param('productId') productId: string) {
return this.productsService.getProductStock(productId);
}

@ApiBearerAuth()
@UseGuards(AuthGuard)
@Post(':productId/review')
@ApiOperation({ summary: 'Submit or Update Product Review' })
async submitReview(
@Param('productId') productId: string,
@CurrentUser() user: User, // Use the correct custom decorator
@Body() dto: CreateReviewDto // Consistent DTO name
) {
return this.productsService.submitReview(user.id, productId, dto);
}

@Delete(':productId/reviews')
@UseGuards(AuthGuard)
@ApiBearerAuth()
@ApiOperation({ summary: 'Delete Product Review' })
async deleteReview(@Param('productId') productId: string, @CurrentUser() user: User) {
return this.productsService.deleteReview(user.id, productId);
}

@Get('view/reviews/:productId')
@ApiOperation({ summary: 'Get Product Details (with Reviews)' })
async getProductDetails(@Param('productId') productId: string) {
return this.productsService.getProductDetails(productId);
}
}
3 changes: 2 additions & 1 deletion src/modules/products/products.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { TypeOrmModule } from '@nestjs/typeorm';
import { Product } from './entities/product.entity';
import { ProductsController } from './products.controller';
import { ProductsService } from './products.service';
import { Review } from './entities/review.entity';
import { UserModule } from '@modules/user/user.module';
import { Cart } from '@modules/dashboard/entities/cart.entity';
import { OrderItem } from '@modules/dashboard/entities/order-items.entity';
Expand All @@ -13,7 +14,6 @@ import { ProductVariant } from './entities/product-variant.entity';
import { Organisation } from '@modules/organisations/entities/organisations.entity';
import { Order } from '@modules/dashboard/entities/order.entity';
import { Comment } from '@modules/comments/entities/comments.entity';

@Module({
imports: [
TypeOrmModule.forFeature([
Expand All @@ -27,6 +27,7 @@ import { Comment } from '@modules/comments/entities/comments.entity';
Order,
OrderItem,
Cart,
Review,
]),
UserModule,
],
Expand Down
Loading

0 comments on commit 878c9c5

Please sign in to comment.