Skip to content

Commit

Permalink
Merge pull request #210 from Roger13579/features/add-isFavorite
Browse files Browse the repository at this point in the history
Features/add is favorite
  • Loading branch information
Roger13579 authored Jun 12, 2024
2 parents bba7af5 + 473c667 commit 0271d56
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 21 deletions.
6 changes: 6 additions & 0 deletions src/dto/product/getProductDetailDto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ import {
export class GetProductDetailDTO {
private readonly _productId: Types.ObjectId;
private readonly _isAdmin: boolean = false;
private readonly _user: IUser | undefined;

get user(): IUser | undefined {
return this._user;
}

get filter() {
return {
Expand All @@ -33,5 +38,6 @@ export class GetProductDetailDTO {
if ((user as IUser | undefined)?.accountType === AccountType.admin) {
this._isAdmin = true;
}
this._user = req.user != null ? (req.user as IUser) : undefined;
}
}
8 changes: 7 additions & 1 deletion src/dto/product/getProductDto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
ProductSortField,
} from '../../types/product.type';
import { AccountType } from '../../types/user.type';
import { omitBy, isNil } from 'lodash';
import { omitBy, isNil, isNaN } from 'lodash';
import { defaultProjection } from '../../utils/product.constants';
import { SortOrder } from '../../types/common.type';

Expand All @@ -31,6 +31,11 @@ export class GetProductDTO {
private readonly _limit: number;
private readonly _sort: Record<string, 1 | -1>;
private readonly _isAdmin: boolean = false;
private readonly _user: IUser | undefined;

get user() {
return this._user;
}

get startAtFrom() {
return this._startAtFrom;
Expand Down Expand Up @@ -151,6 +156,7 @@ export class GetProductDTO {
if ((req.user as IUser)?.accountType === AccountType.admin) {
this._isAdmin = true;
}
this._user = req.user != null ? (req.user as IUser) : undefined;

this._types = types?.split(',') as ProductType[];
this._genres = genres?.split(',') as MovieGenre[];
Expand Down
1 change: 1 addition & 0 deletions src/routes/ticketRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export class TicketRoute extends BaseRoute {
required: false,
description: '精準搜尋:票券狀態',
type: 'string',
enum: ["verified", "unverified", "refunded", "expired", "cancelled", "pending", "transfer"],
schema:{
$ref:"#/definitions/CustomGetTicketStatusQuery"
}
Expand Down
47 changes: 41 additions & 6 deletions src/service/productService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import { TagRepository } from '../repository/tagRepository';
import { GetProductDetailDTO } from '../dto/product/getProductDetailDto';
import { SortOrder } from '../types/common.type';
import { IProduct } from '../models/product';
import { TCreateInvalidProductParam } from '../types/product.type';
import {
ProductDocumentWithFavorite,
TCreateInvalidProductParam,
} from '../types/product.type';
import { ITagId } from '../types/tag.type';

export class ProductService {
Expand Down Expand Up @@ -62,7 +65,7 @@ export class ProductService {
};

public findProducts = async (getProductDto: GetProductDTO) => {
const { sellStartAtFrom, sellStartAtTo, startAtFrom, startAtTo } =
const { sellStartAtFrom, sellStartAtTo, startAtFrom, startAtTo, user } =
getProductDto;

// 確認時間順序
Expand All @@ -76,23 +79,55 @@ export class ProductService {
],
SortOrder.asc,
);
const result = await this.productRepository.findProducts(getProductDto);

return await this.productRepository.findProducts(getProductDto);
let favoriteProductIds: string[];
if (user && user.favorites) {
favoriteProductIds = user.favorites.map((favorite) =>
favorite.productId.toString(),
);
}
result.docs = await Promise.all(
result.docs.map(async (doc) => {
let isFavorite = false;
if (user) {
if (favoriteProductIds.includes(doc._id.toString())) {
isFavorite = true;
}
}
return {
...doc.toObject(),
isFavorite: isFavorite,
} as ProductDocumentWithFavorite;
}),
);
return result;
};

public getProductDetail = async (
getProductDetailDto: GetProductDetailDTO,
) => {
const product =
await this.productRepository.findProductDetail(getProductDetailDto);
const product = (await this.productRepository.findProductDetail(
getProductDetailDto,
)) as ProductDocumentWithFavorite;

if (!product) {
throwError(
CustomResponseType.PRODUCT_NOT_FOUND_MESSAGE,
CustomResponseType.PRODUCT_NOT_FOUND,
);
}
return product;
let favoriteProductIds: string[] = [];
if (getProductDetailDto.user && getProductDetailDto.user.favorites) {
favoriteProductIds = getProductDetailDto.user.favorites.map((favorite) =>
favorite.productId.toString(),
);
}

return {
...product.toObject(),
isFavorite: favoriteProductIds.includes(product._id.toString()),
};
};

public deleteProducts = async (ids: Types.ObjectId[]) => {
Expand Down
2 changes: 2 additions & 0 deletions src/swagger/definition/product/general.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export const ProductItem = {
startAt: moment().add(2, 'day').add(4, 'hour').toISOString(),
tags: [{ tagId: '123' }, { tagId: '123' }],
photoPath: '',
isFavorite: false,
};

/**
Expand Down Expand Up @@ -85,6 +86,7 @@ export const GetProductDetailSuccess = {
$startAt: moment().add(2, 'day').add(4, 'hour').toISOString(),
$tags: [{ tagId: '123' }, { tagId: '123' }],
$photoPath: '',
$isFavorite: false,
...ProductDetailItem,
},
};
Expand Down
26 changes: 12 additions & 14 deletions src/swagger/definition/user/general.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,17 @@ import { CustomResponseType } from '../../../types/customResponseType';
import { PaginationSuccess } from '../common';

const favorite = {
product: {
$_id: '665b00748f529f5f17923acd',
title: '這是個很棒的電影名稱喔',
type: 'premier',
genre: 'action',
price: 1100,
soldAmount: 0,
amount: 100,
isLaunched: true,
photoPath: 'https://images.unsplash.com/photo-1554080353-a576cf803bda',
sellStartAt: new Date().toISOString(),
sellEndAt: new Date().toISOString(),
},
$_id: '665b00748f529f5f17923acd',
title: '這是個很棒的電影名稱喔',
type: 'premier',
genre: 'action',
price: 1100,
soldAmount: 0,
amount: 100,
isLaunched: true,
photoPath: 'https://images.unsplash.com/photo-1554080353-a576cf803bda',
sellStartAt: new Date().toISOString(),
sellEndAt: new Date().toISOString(),
};

export const GetFavoriteSuccess = {
Expand All @@ -32,7 +30,7 @@ export const EditFavoriteSuccess = {
$data: {
$favorites: [
{
$productId: favorite.product.$_id,
$productId: favorite.$_id,
},
],
},
Expand Down
1 change: 1 addition & 0 deletions src/types/cart.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ interface ICartPaginationItem extends ITimestamp {
| 'amount'
| 'isLaunched'
| 'photoPath'
| 'sellStartAt'
| 'sellEndAt'
>;
amount: number;
Expand Down
9 changes: 9 additions & 0 deletions src/types/product.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,13 @@ export interface IInvalidProduct extends ISubResponse {
product: unknown;
}

export interface IProductWithFavorite extends IProduct {
isFavorite: boolean;
}

export type ProductDocumentWithFavorite = Document &
IProductWithFavorite & {
_id: Types.ObjectId;
};

export type TCreateInvalidProductParam = (product: unknown) => IInvalidProduct;

0 comments on commit 0271d56

Please sign in to comment.