diff --git a/src/modules/product/controllers/product.controller.ts b/src/modules/product/controllers/product.controller.ts index 09a2605..325c540 100644 --- a/src/modules/product/controllers/product.controller.ts +++ b/src/modules/product/controllers/product.controller.ts @@ -50,6 +50,7 @@ export class ProductController { @ApiQuery({ name: 'orderBy', required: false, type: String }) @ApiQuery({ name: 'order', required: false, enum: ['asc', 'desc'] }) @ApiQuery({ name: 'isActive', required: false, type: Boolean }) + @ApiQuery({ name: 'parentId', required: false, type: String, description: 'Parent category id, or "null" for roots' }) async findAllCategories(@Query() dto: FindCategoriesDto) { const result = await this.categoryService.findAll(dto); return result; diff --git a/src/modules/product/dto/find-categories.dto.ts b/src/modules/product/dto/find-categories.dto.ts index b6f37a1..3109844 100644 --- a/src/modules/product/dto/find-categories.dto.ts +++ b/src/modules/product/dto/find-categories.dto.ts @@ -36,4 +36,12 @@ export class FindCategoriesDto { @Type(() => Boolean) @ApiPropertyOptional({ example: true }) isActive?: boolean; + + @IsOptional() + @IsString() + @ApiPropertyOptional({ + description: 'Filter by parent category id. Use "null" for root categories only.', + example: 'null', + }) + parentId?: string; } diff --git a/src/modules/product/repositories/category.repository.ts b/src/modules/product/repositories/category.repository.ts index 31bc806..d95b7a5 100644 --- a/src/modules/product/repositories/category.repository.ts +++ b/src/modules/product/repositories/category.repository.ts @@ -11,6 +11,7 @@ type FindCategoriesOpts = { orderBy?: string; order?: 'asc' | 'desc'; isActive?: boolean; + parentId?: string; }; export type CategoryTreeNode = { @@ -73,7 +74,7 @@ export class CategoryRepository extends EntityRepository { } async findAllPaginated(opts: FindCategoriesOpts = {}): Promise> { - const { page = 1, limit = 10, search, orderBy = 'createdAt', order = 'desc', isActive } = opts; + const { page = 1, limit = 10, search, orderBy = 'order', order = 'asc', isActive, parentId } = opts; const offset = (page - 1) * limit; @@ -83,6 +84,12 @@ export class CategoryRepository extends EntityRepository { where.isActive = isActive; } + if (parentId === 'null') { + where.parent = null; + } else if (parentId) { + where.parent = parentId; + } + if (search) { where.$or = [ { title: { $ilike: `%${search}%` } }, @@ -91,7 +98,7 @@ export class CategoryRepository extends EntityRepository { const allCategories = await this.find(where, { orderBy: { [orderBy]: order.toLowerCase() as 'asc' | 'desc' }, - populate: ['parent'], + populate: ['parent', 'children'], }); const total = allCategories.length;