diff --git a/src/modules/dmenu/DTO/find-restaurants.dto.ts b/src/modules/dmenu/DTO/find-restaurants.dto.ts new file mode 100644 index 0000000..1840dff --- /dev/null +++ b/src/modules/dmenu/DTO/find-restaurants.dto.ts @@ -0,0 +1,73 @@ +import { + IsOptional, + IsString, + IsNumber, + Min, + IsIn, + IsEnum, + IsBoolean, +} from 'class-validator'; +import { Type, Transform } from 'class-transformer'; +import { ApiPropertyOptional } from '@nestjs/swagger'; +import { PlanEnum } from '../interface/plan.interface'; + +const sortOrderOptions = ['asc', 'desc'] as const; +type SortOrder = (typeof sortOrderOptions)[number]; + +export class FindRestaurantsDto { + @ApiPropertyOptional({ default: 1, minimum: 1 }) + @IsOptional() + @Type(() => Number) + @IsNumber() + @Min(1) + page: number = 1; + + @ApiPropertyOptional({ default: 10, minimum: 1 }) + @IsOptional() + @Type(() => Number) + @IsNumber() + @Min(1) + limit: number = 10; + + @ApiPropertyOptional({ + description: 'Search by name, slug, domain, or address', + }) + @IsOptional() + @IsString() + search?: string; + + @ApiPropertyOptional({ + description: 'Filter by active status', + type: Boolean, + }) + @IsOptional() + @Transform(({ value }) => { + if (value === 'true') return true; + if (value === 'false') return false; + return value; + }) + @IsBoolean() + isActive?: boolean; + + @ApiPropertyOptional({ + enum: PlanEnum, + description: 'Filter by plan type', + }) + @IsOptional() + @IsEnum(PlanEnum) + plan?: PlanEnum; + + @ApiPropertyOptional({ default: 'createdAt' }) + @IsOptional() + @IsString() + orderBy: string = 'createdAt'; + + @ApiPropertyOptional({ + enum: sortOrderOptions, + default: 'desc', + }) + @IsOptional() + @IsIn(sortOrderOptions) + order: SortOrder = 'desc'; +} + diff --git a/src/modules/dmenu/dmenu.controller.ts b/src/modules/dmenu/dmenu.controller.ts index 12d31ca..eb2cad0 100644 --- a/src/modules/dmenu/dmenu.controller.ts +++ b/src/modules/dmenu/dmenu.controller.ts @@ -1,4 +1,4 @@ -import { Body, Controller, Delete, Get, Param, Patch, Post } from "@nestjs/common"; +import { Body, Controller, Delete, Get, Param, Patch, Post, Query } from "@nestjs/common"; import { ApiBearerAuth, ApiOperation, ApiParam, ApiTags } from "@nestjs/swagger"; import { ContactService } from "./providers/contact.service"; @@ -8,6 +8,7 @@ import { CreateIconDto } from "./DTO/create-icon.dto"; import { UpdateIconDto } from "./DTO/update-icon.dto"; import { CreateGroupDto } from "./DTO/create-group.dto"; import { UpdateGroupDto } from "./DTO/update-group.dto"; +import { FindRestaurantsDto } from "./DTO/find-restaurants.dto"; import { AuthGuards } from "../../common/decorators/auth-guard.decorator"; import { PermissionsDec } from "../../common/decorators/permission.decorator"; import { PermissionEnum } from "../users/enums/permission.enum"; @@ -103,7 +104,7 @@ export class DmenuController { @Get('restaurants') @ApiOperation({ summary: "Get all restaurants" }) - findAllRestaurant() { - return this.restaurantService.findAll(); + findAllRestaurant(@Query() queryDto: FindRestaurantsDto) { + return this.restaurantService.findAll(queryDto); } } diff --git a/src/modules/dmenu/interface/plan.interface.ts b/src/modules/dmenu/interface/plan.interface.ts new file mode 100644 index 0000000..a5cb074 --- /dev/null +++ b/src/modules/dmenu/interface/plan.interface.ts @@ -0,0 +1,4 @@ +export enum PlanEnum { + Base = 'base', + Premium = 'premium', +} diff --git a/src/modules/dmenu/providers/restaurant.service.ts b/src/modules/dmenu/providers/restaurant.service.ts index 25235cd..6b58fe0 100644 --- a/src/modules/dmenu/providers/restaurant.service.ts +++ b/src/modules/dmenu/providers/restaurant.service.ts @@ -6,6 +6,7 @@ import { catchError, firstValueFrom, throwError } from "rxjs"; import { IDmenuConfig } from "../../../configs/icons.config"; import { DMENU_CONFIG } from "../constants"; +import { FindRestaurantsDto } from "../DTO/find-restaurants.dto"; @Injectable() export class RestaurantService { @@ -24,15 +25,39 @@ export class RestaurantService { }; } - async findAll() { + async findAll(queryDto: FindRestaurantsDto) { try { + const params: Record = { + page: queryDto.page || 1, + limit: queryDto.limit || 10, + orderBy: queryDto.orderBy || 'createdAt', + order: queryDto.order || 'desc', + }; + + if (queryDto.search) { + params.search = queryDto.search; + } + + if (queryDto.isActive !== undefined) { + params.isActive = queryDto.isActive; + } + + if (queryDto.plan) { + params.plan = queryDto.plan; + } + const { data } = await firstValueFrom( - this.httpService.get(`${this.config.baseUrl}/super-admin/restaurants`, { headers: this.getHeaders() }).pipe( - catchError((err: AxiosError) => { - this.logger.error(`Failed to fetch restaurants: ${err.message}`, err.stack); - return throwError(() => err); - }), - ), + this.httpService + .get(`${this.config.baseUrl}/super-admin/restaurants`, { + params, + headers: this.getHeaders(), + }) + .pipe( + catchError((err: AxiosError) => { + this.logger.error(`Failed to fetch restaurants: ${err.message}`, err.stack); + return throwError(() => err); + }), + ), ); return data; } catch (error: unknown) {