Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Headless/tahsin/review/get review #498

Draft
wants to merge 21 commits into
base: multi-vendor-backend
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
32 changes: 28 additions & 4 deletions packages/headless/src/database/mongodb/order/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import {
CreateProductOrderDetails,
} from '@bs-commerce/models';
import { CartModel } from '../cart/cart.model';
import { ReviewModel } from '../review/review.model';
import { Review } from 'src/entity/review';

export class OrderDatabase implements IOrderDatabase {
async populateItemsInCart(
Expand Down Expand Up @@ -263,9 +265,9 @@ export class OrderDatabase implements IOrderDatabase {
): Promise<OrderEntity[]> {
const { shippingStatus, orderStatus, paymentStatus, startDate, endDate } =
query;
const sort ={
orderedDate: -1
}
const sort = {
orderedDate: -1,
};
const queryParams = {
...(shippingStatus && { shippingStatus }),
...(orderStatus && { orderStatus }),
Expand All @@ -278,6 +280,28 @@ export class OrderDatabase implements IOrderDatabase {
...(endDate && { $lte: new Date(endDate) }),
};
}
return await OrderModel.find(queryParams).skip(skip).limit(limit).sort(sort).lean();
return await OrderModel.find(queryParams)
.skip(skip)
.limit(limit)
.sort(sort)
.lean();
}

async createReview(review: any): Promise<Review | null>{
try{
return await ReviewModel.create(review);
}catch (err) {
console.log(err);
return null;
}
}

async findReview(query: Record<string,any>): Promise<Review[] | null>{
try{
return await ReviewModel.find(query).lean().exec();
}catch (err) {
console.log(err);
return null;
}
}
}
37 changes: 18 additions & 19 deletions packages/headless/src/database/mongodb/review/review.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,35 +17,34 @@ const ReviewSchema = new Schema<Review>(
type: String,
required: true,
},
comments: [
text: String,
image: [
{
id: {
type: String,
default: () => randomUUID(),
unique: true
},
url: String,
_id: false
}
],
reply:{
commentedBy:{
type: String,
enum : ['CUSTOMER','STORE_ADMIN','BRANCH_MANAGER']
enum : ['STORE_ADMIN','BRANCH_MANAGER']
},
image: [
{
url: String,
_id: false,
},
],
text: String,
createdAt: {
type: Date,
default: Date.now,
image: {
type: [String],
default: undefined,
},
},
],
createdAt: Date
},
userId: {
type: String,
required: false,
},

rating: {
type: Number,
min: 1,
max: 5
}
},
{
timestamps: true,
Expand Down
3 changes: 2 additions & 1 deletion packages/headless/src/entity/branch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ export class BranchPhoto{

export enum InActiveReason{
BLOCKED_BY_ADMIN = 'BLOCKED_BY_ADMIN',
UNDER_MAINTENANCE = 'UNDER_MAINTENANCE'
UNDER_MAINTENANCE = 'UNDER_MAINTENANCE',
ADMIN_APPROVAL = 'NEED ADMIN APPROVAL'
}
export class Branch{
id: string;
Expand Down
20 changes: 16 additions & 4 deletions packages/headless/src/entity/review.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
import { Exclude } from "class-transformer";

export class Review{
id: string;
productId: string;
orderId: string;
text: string;
image: ReviewPhoto[];
userId?: string;
comments: Comment[];
reply: Comment;
rating: number;
}

export class ReviewPhoto{
url: string;
}

export class Comment{
id: string;
commentedBy: Commenters;
image?: string[];
text: string;
image: string[];
createdAt: Date;
}

export enum Commenters{
CUSTOMER = 'CUSTOMER',
STORE_ADMIN = 'STORE_ADMIN',
BRANCH_MANAGER = 'BRANCH_MANAGER'
}

export class ProductReviewListEntity{
productId: string;
reviews: Review[];
}
5 changes: 4 additions & 1 deletion packages/headless/src/modules/order/order.rest.module.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { OrderReviewController } from './rest/review.controller';
import { Module } from '@nestjs/common';
import { ResolveDatabaseDependency } from 'src/database/database.resolver';
import { OrderRepository } from './repositories';
Expand All @@ -6,12 +7,14 @@ import { OrderAdminController } from './rest/admin.controlller';
import { OrderCustomerController } from './rest/customer.controller';
import { OrderAdminService } from './services/admin.service';
import { OrderCustomerService } from './services/customer.service';
import { OrderReviewService } from './services/review.service';

@Module({
controllers: [OrderCustomerController, OrderAdminController],
controllers: [OrderCustomerController, OrderAdminController, OrderReviewController],
providers: [
OrderCustomerService,
OrderAdminService,
OrderReviewService,
OrderRepository,
{
provide: IOrderDatabase,
Expand Down
12 changes: 11 additions & 1 deletion packages/headless/src/modules/order/repositories/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import {
CreateProductOrderDetails,
} from '@bs-commerce/models';
import { Injectable } from '@nestjs/common';
import { randomInt } from 'crypto';
import { randomInt, randomUUID } from 'crypto';
import { CreateReviewResponse } from 'models';

import {
GetAllOrderQueryEntity,
Expand All @@ -17,6 +18,7 @@ import {
CartResponse,
Cart,
} from 'src/entity/order';
import { Review } from 'src/entity/review';
import { IOrderDatabase } from './order.db.interface';

@Injectable()
Expand Down Expand Up @@ -113,4 +115,12 @@ export class OrderRepository {
): Promise<OrderEntity[]> {
return await this.db.getOrderList(query, skip, limit);
}

async createReview(review: any):Promise<Review | null>{
return await this.db.createReview(review);
}

async findReview(query: Record<string,any>): Promise<Review[] | null>{
return await this.db.findReview(query);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {
OrderStatEntity,
ProductOrder,
} from 'src/entity/order';
import { CreateReviewResponse } from 'models';
import { Review } from 'src/entity/review';

@Injectable()
export abstract class IOrderDatabase {
Expand Down Expand Up @@ -46,4 +48,6 @@ export abstract class IOrderDatabase {
items: CartItem[],
) => Promise<CartResponse | null>;
abstract clearCart: (userId: string) => Promise<CartResponse | null>;
abstract createReview: (review: any) => Promise<Review | null>
abstract findReview: (query: Record<string,any>)=> Promise<Review[] | null>
}
66 changes: 66 additions & 0 deletions packages/headless/src/modules/order/rest/dto/create.review.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { HttpStatus } from "@nestjs/common";
import { ApiProperty } from "@nestjs/swagger";
import { Type } from "class-transformer";
import { IsString, IsNotEmpty, IsOptional, IsArray, IsNumber, IsObject, Max, Min } from "class-validator";
import { CreateReviewErrorResponse, CreateReviewSuccessResponse, CreateReviewErrorMessage, ICreateReview } from "models";
import { Commenters } from "src/entity/review";
import { CommentDto, ReviewDto, ReviewPhotoDto } from "./review.dto";
import { ValidateNested as CustomValidator } from 'src/decorators/service.validator';

export class CreateReviewDto implements ICreateReview{
@ApiProperty({ example: '6e9fb5dc-a3ad-4d35-81d2-16fc6e2dc54e'})
@IsString()
@IsNotEmpty()
productId: string;

@ApiProperty({ example: '003889009372785'})
@IsString()
orderId: string;

@ApiProperty()
@IsOptional()
@IsString()
text?: string;

@ApiProperty({ type: [ReviewPhotoDto]})
@IsOptional()
@Type(() => ReviewPhotoDto)
image?: ReviewPhotoDto[];

@ApiProperty()
@IsNumber()
@IsOptional()
@Min(1)
@Max(5)
rating?: number;
}

export class CreateReviewSuccessResponseDto implements CreateReviewSuccessResponse{
@ApiProperty({ default: HttpStatus.OK })
code: number;

@ApiProperty()
data: ReviewDto;
}

export class CreateReviewErrorResponseDto implements CreateReviewErrorResponse {
@ApiProperty({ default: HttpStatus.BAD_REQUEST })
code?: number;

@ApiProperty()
error:
| CreateReviewErrorMessage.INVALID_PRODUCT_ID
| CreateReviewErrorMessage.INVALID_ORDER_ID
| CreateReviewErrorMessage.INVALID_USER_ID
| CreateReviewErrorMessage.CANNOT_CREATE_REVIEW
| CreateReviewErrorMessage.CANNOT_UPLOAD_MORE_THAN_5_PHOTOS
| CreateReviewErrorMessage.CANNOT_REPLY
| CreateReviewErrorMessage.ALREADY_REVIEWED_ONCE

@ApiProperty()
errors: string[];
}

export type CreateReviewResponseDto =
| CreateReviewErrorResponseDto
| CreateReviewSuccessResponseDto;
43 changes: 43 additions & 0 deletions packages/headless/src/modules/order/rest/dto/product.review.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { HttpStatus } from "@nestjs/common";
import { ApiProperty } from "@nestjs/swagger";
import { Exclude, Type } from "class-transformer";
import { IsArray, IsNotEmpty, IsNumber, IsObject, IsOptional, IsString } from "class-validator";
import { IProductReviewList, ProductReviewErrorMessage, ProductReviewErrorResponse, ProductReviewSuccessResponse } from "models";
import { ReviewPhotoDto, CommentDto, ReviewDto } from "./review.dto";

export class ProductReviewListDto implements IProductReviewList{
@ApiProperty()
@IsNotEmpty()
productId: string;

@ApiProperty({ type: [ReviewDto]})
@IsNotEmpty()
@Type(() => ReviewDto)
@IsArray()
reviews: ReviewDto[]
}

export class ProductReviewSuccessResponseDto implements ProductReviewSuccessResponse{
@ApiProperty({ default: HttpStatus.OK })
code: number;

@ApiProperty()
data: ProductReviewListDto;
}

export class ProductReviewErrorResponseDto implements ProductReviewErrorResponse {
@ApiProperty({ default: HttpStatus.BAD_REQUEST })
code?: number;

@ApiProperty()
error:
| ProductReviewErrorMessage.CANNOT_FIND_REVIEW
| ProductReviewErrorMessage.INVALID_PRODUCT_ID

@ApiProperty()
errors: string[];
}

export type ProductReviewResponseDto =
| ProductReviewErrorResponseDto
| ProductReviewSuccessResponseDto;
Loading