From 91d4625fcdf26dd45e05492849c74ff597ce6161 Mon Sep 17 00:00:00 2001 From: pradeepkumar Date: Sun, 1 Feb 2026 15:04:28 +0530 Subject: [PATCH] feat: Add public endpoint and service to retrieve and merge filterable profile fields with options. --- .../profile-fields.controller.ts | 8 +++ src/profile-fields/profile-fields.service.ts | 68 ++++++++++++++++++- 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/profile-fields/profile-fields.controller.ts b/src/profile-fields/profile-fields.controller.ts index 4b0ddce..21c3821 100644 --- a/src/profile-fields/profile-fields.controller.ts +++ b/src/profile-fields/profile-fields.controller.ts @@ -16,6 +16,7 @@ import { CreateFieldDto, UpdateFieldDto } from './dto'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { RolesGuard } from '../auth/guards/roles.guard'; import { Roles } from '../auth/decorators/roles.decorator'; +import { Public } from '../auth/decorators/public.decorator'; import { UserRole } from '@prisma/client'; @ApiTags('Profile Fields') @@ -23,6 +24,13 @@ import { UserRole } from '@prisma/client'; export class ProfileFieldsController { constructor(private readonly fieldsService: ProfileFieldsService) {} + @Public() + @Get('filterable') + @ApiOperation({ summary: 'Get all filterable fields with options (Public)' }) + getFilterableFields() { + return this.fieldsService.getFilterableFields(); + } + @Post() @UseGuards(JwtAuthGuard, RolesGuard) @Roles(UserRole.ADMIN) diff --git a/src/profile-fields/profile-fields.service.ts b/src/profile-fields/profile-fields.service.ts index 6b0ed46..99cd1d4 100644 --- a/src/profile-fields/profile-fields.service.ts +++ b/src/profile-fields/profile-fields.service.ts @@ -1,5 +1,5 @@ import { Injectable, NotFoundException, ConflictException, BadRequestException } from '@nestjs/common'; -import { Prisma } from '@prisma/client'; +import { Prisma, FieldType } from '@prisma/client'; import { PrismaService } from '../prisma'; import { CreateFieldDto, UpdateFieldDto } from './dto'; @@ -230,4 +230,70 @@ export class ProfileFieldsService { return { success: true, updated: updates.length }; } + + /** + * Get all filterable fields (public endpoint for search filters) + * Returns fields with CHECKBOX_GROUP, SELECT, MULTI_SELECT types that have options + */ + async getFilterableFields() { + const filterableTypes: FieldType[] = [FieldType.CHECKBOX_GROUP, FieldType.SELECT, FieldType.MULTI_SELECT]; + + const fields = await this.prisma.profileField.findMany({ + where: { + isActive: true, + fieldType: { in: filterableTypes }, + options: { not: Prisma.JsonNull }, + }, + select: { + id: true, + name: true, + slug: true, + fieldType: true, + options: true, + section: { + select: { + id: true, + name: true, + slug: true, + }, + }, + }, + orderBy: [ + { section: { sortOrder: 'asc' } }, + { sortOrder: 'asc' }, + ], + }); + + // Group fields by slug to merge options from different sections (same field in different agent types) + const mergedFields = new Map(); + + for (const field of fields) { + const existingField = mergedFields.get(field.slug); + const fieldOptions = (field.options as { label: string; value: string }[]) || []; + + if (existingField) { + // Merge options, avoiding duplicates by value + const existingValues = new Set(existingField.options.map(o => o.value)); + for (const opt of fieldOptions) { + if (!existingValues.has(opt.value)) { + existingField.options.push(opt); + } + } + } else { + mergedFields.set(field.slug, { + slug: field.slug, + name: field.name, + fieldType: field.fieldType, + options: [...fieldOptions], + }); + } + } + + return Array.from(mergedFields.values()); + } }