2026-01-11 20:59:12 +05:30
|
|
|
import {
|
|
|
|
|
Controller,
|
|
|
|
|
Get,
|
|
|
|
|
Post,
|
|
|
|
|
Put,
|
|
|
|
|
Delete,
|
|
|
|
|
Body,
|
|
|
|
|
Param,
|
|
|
|
|
Query,
|
2026-03-28 18:46:49 +05:30
|
|
|
Req,
|
2026-01-11 20:59:12 +05:30
|
|
|
UseGuards,
|
|
|
|
|
ParseUUIDPipe,
|
|
|
|
|
} from '@nestjs/common';
|
|
|
|
|
import {
|
|
|
|
|
ApiTags,
|
|
|
|
|
ApiOperation,
|
|
|
|
|
ApiResponse,
|
|
|
|
|
ApiBearerAuth,
|
|
|
|
|
} from '@nestjs/swagger';
|
|
|
|
|
import { AgentsService } from './agents.service';
|
|
|
|
|
import {
|
|
|
|
|
CreateAgentProfileDto,
|
|
|
|
|
UpdateAgentProfileDto,
|
|
|
|
|
SearchAgentsDto,
|
2026-01-24 21:06:08 +05:30
|
|
|
SaveFieldValuesDto,
|
2026-01-11 20:59:12 +05:30
|
|
|
} from './dto';
|
|
|
|
|
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
|
|
|
|
|
import { RolesGuard } from '../auth/guards/roles.guard';
|
2026-03-28 18:46:49 +05:30
|
|
|
import { OptionalAuthGuard } from '../auth/guards/optional-auth.guard';
|
2026-01-11 20:59:12 +05:30
|
|
|
import { Roles } from '../auth/decorators/roles.decorator';
|
2026-01-11 22:09:50 +05:30
|
|
|
import { Public } from '../auth/decorators/public.decorator';
|
2026-01-11 20:59:12 +05:30
|
|
|
import { CurrentUser } from '../auth/decorators/current-user.decorator';
|
2026-01-28 13:48:14 +05:30
|
|
|
import { UserRole, VerificationStatus } from '@prisma/client';
|
2026-01-11 20:59:12 +05:30
|
|
|
|
|
|
|
|
@ApiTags('agents')
|
|
|
|
|
@Controller('agents')
|
|
|
|
|
export class AgentsController {
|
|
|
|
|
constructor(private readonly agentsService: AgentsService) {}
|
|
|
|
|
|
2026-01-11 22:09:50 +05:30
|
|
|
// Public endpoints - accessible by anyone
|
2026-01-11 20:59:12 +05:30
|
|
|
|
|
|
|
|
@Get()
|
2026-01-11 22:09:50 +05:30
|
|
|
@Public()
|
2026-01-11 20:59:12 +05:30
|
|
|
@ApiOperation({ summary: 'Search and list agents' })
|
|
|
|
|
@ApiResponse({ status: 200, description: 'Agents retrieved successfully' })
|
|
|
|
|
async searchAgents(@Query() dto: SearchAgentsDto) {
|
|
|
|
|
return this.agentsService.searchAgents(dto);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Get('featured')
|
2026-01-11 22:09:50 +05:30
|
|
|
@Public()
|
2026-01-11 20:59:12 +05:30
|
|
|
@ApiOperation({ summary: 'Get featured agents' })
|
|
|
|
|
@ApiResponse({
|
|
|
|
|
status: 200,
|
|
|
|
|
description: 'Featured agents retrieved successfully',
|
|
|
|
|
})
|
|
|
|
|
async getFeaturedAgents(@Query('limit') limit?: number) {
|
|
|
|
|
return this.agentsService.getFeaturedAgents(limit || 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Get('top-rated')
|
2026-01-11 22:09:50 +05:30
|
|
|
@Public()
|
2026-01-11 20:59:12 +05:30
|
|
|
@ApiOperation({ summary: 'Get top rated agents' })
|
|
|
|
|
@ApiResponse({
|
|
|
|
|
status: 200,
|
|
|
|
|
description: 'Top rated agents retrieved successfully',
|
|
|
|
|
})
|
|
|
|
|
async getTopRatedAgents(@Query('limit') limit?: number) {
|
|
|
|
|
return this.agentsService.getTopRatedAgents(limit || 10);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-11 22:09:50 +05:30
|
|
|
// Agent-only endpoints - requires AGENT role
|
2026-01-11 20:59:12 +05:30
|
|
|
|
|
|
|
|
@Get('profile/me')
|
2026-01-11 22:09:50 +05:30
|
|
|
@UseGuards(JwtAuthGuard, RolesGuard)
|
|
|
|
|
@Roles(UserRole.AGENT)
|
2026-01-11 20:59:12 +05:30
|
|
|
@ApiBearerAuth()
|
|
|
|
|
@ApiOperation({ summary: 'Get current user agent profile' })
|
|
|
|
|
@ApiResponse({ status: 200, description: 'Profile retrieved successfully' })
|
|
|
|
|
@ApiResponse({ status: 404, description: 'Profile not found' })
|
|
|
|
|
async getMyProfile(@CurrentUser('id') userId: string) {
|
|
|
|
|
return this.agentsService.getProfile(userId);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-24 23:10:05 +05:30
|
|
|
@Get('profile/field-values')
|
|
|
|
|
@UseGuards(JwtAuthGuard, RolesGuard)
|
|
|
|
|
@Roles(UserRole.AGENT)
|
|
|
|
|
@ApiBearerAuth()
|
|
|
|
|
@ApiOperation({ summary: 'Get dynamic field values for agent profile' })
|
|
|
|
|
@ApiResponse({ status: 200, description: 'Field values retrieved successfully' })
|
|
|
|
|
@ApiResponse({ status: 404, description: 'Profile not found' })
|
|
|
|
|
async getFieldValues(@CurrentUser('id') userId: string) {
|
|
|
|
|
return this.agentsService.getFieldValues(userId);
|
2026-01-11 20:59:12 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Post('profile')
|
2026-01-11 22:09:50 +05:30
|
|
|
@UseGuards(JwtAuthGuard, RolesGuard)
|
|
|
|
|
@Roles(UserRole.AGENT)
|
2026-01-11 20:59:12 +05:30
|
|
|
@ApiBearerAuth()
|
|
|
|
|
@ApiOperation({ summary: 'Create agent profile' })
|
|
|
|
|
@ApiResponse({ status: 201, description: 'Profile created successfully' })
|
|
|
|
|
@ApiResponse({ status: 409, description: 'Profile already exists' })
|
|
|
|
|
async createProfile(
|
|
|
|
|
@CurrentUser('id') userId: string,
|
|
|
|
|
@Body() dto: CreateAgentProfileDto,
|
|
|
|
|
) {
|
|
|
|
|
return this.agentsService.createProfile(userId, dto);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Put('profile')
|
2026-01-11 22:09:50 +05:30
|
|
|
@UseGuards(JwtAuthGuard, RolesGuard)
|
|
|
|
|
@Roles(UserRole.AGENT)
|
2026-01-11 20:59:12 +05:30
|
|
|
@ApiBearerAuth()
|
|
|
|
|
@ApiOperation({ summary: 'Update current user agent profile' })
|
|
|
|
|
@ApiResponse({ status: 200, description: 'Profile updated successfully' })
|
|
|
|
|
@ApiResponse({ status: 404, description: 'Profile not found' })
|
|
|
|
|
async updateProfile(
|
|
|
|
|
@CurrentUser('id') userId: string,
|
|
|
|
|
@Body() dto: UpdateAgentProfileDto,
|
|
|
|
|
) {
|
|
|
|
|
return this.agentsService.updateProfile(userId, dto);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-24 21:06:08 +05:30
|
|
|
@Put('profile/field-values')
|
|
|
|
|
@UseGuards(JwtAuthGuard, RolesGuard)
|
|
|
|
|
@Roles(UserRole.AGENT)
|
|
|
|
|
@ApiBearerAuth()
|
|
|
|
|
@ApiOperation({ summary: 'Save dynamic field values for agent profile' })
|
|
|
|
|
@ApiResponse({ status: 200, description: 'Field values saved successfully' })
|
|
|
|
|
@ApiResponse({ status: 404, description: 'Profile not found' })
|
|
|
|
|
async saveFieldValues(
|
|
|
|
|
@CurrentUser('id') userId: string,
|
|
|
|
|
@Body() dto: SaveFieldValuesDto,
|
|
|
|
|
) {
|
|
|
|
|
return this.agentsService.saveFieldValues(userId, dto);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-09 00:33:54 +05:30
|
|
|
// Notification preferences endpoints
|
|
|
|
|
|
|
|
|
|
@Get('preferences/notifications')
|
|
|
|
|
@UseGuards(JwtAuthGuard, RolesGuard)
|
|
|
|
|
@Roles(UserRole.AGENT)
|
|
|
|
|
@ApiBearerAuth()
|
|
|
|
|
@ApiOperation({ summary: 'Get notification preferences (Agents only)' })
|
|
|
|
|
@ApiResponse({
|
|
|
|
|
status: 200,
|
|
|
|
|
description: 'Notification preferences retrieved',
|
|
|
|
|
schema: {
|
|
|
|
|
example: {
|
|
|
|
|
email: {
|
|
|
|
|
new_leads: true,
|
|
|
|
|
messages: true,
|
|
|
|
|
connection_requests: true,
|
|
|
|
|
property_updates: false,
|
|
|
|
|
marketing: false,
|
|
|
|
|
},
|
|
|
|
|
push: {
|
|
|
|
|
push_messages: true,
|
|
|
|
|
push_leads: true,
|
|
|
|
|
push_reminders: false,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
async getNotificationPreferences(@CurrentUser('id') userId: string) {
|
|
|
|
|
return this.agentsService.getNotificationPreferences(userId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Put('preferences/notifications')
|
|
|
|
|
@UseGuards(JwtAuthGuard, RolesGuard)
|
|
|
|
|
@Roles(UserRole.AGENT)
|
|
|
|
|
@ApiBearerAuth()
|
|
|
|
|
@ApiOperation({ summary: 'Update notification preferences (Agents only)' })
|
|
|
|
|
@ApiResponse({ status: 200, description: 'Notification preferences updated' })
|
|
|
|
|
async updateNotificationPreferences(
|
|
|
|
|
@CurrentUser('id') userId: string,
|
|
|
|
|
@Body()
|
|
|
|
|
data: {
|
|
|
|
|
email?: Record<string, boolean>;
|
|
|
|
|
push?: Record<string, boolean>;
|
|
|
|
|
},
|
|
|
|
|
) {
|
|
|
|
|
return this.agentsService.updateNotificationPreferences(userId, data);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-09 00:55:55 +05:30
|
|
|
// Privacy preferences endpoints
|
|
|
|
|
|
|
|
|
|
@Get('preferences/privacy')
|
|
|
|
|
@UseGuards(JwtAuthGuard, RolesGuard)
|
|
|
|
|
@Roles(UserRole.AGENT)
|
|
|
|
|
@ApiBearerAuth()
|
|
|
|
|
@ApiOperation({ summary: 'Get privacy preferences (Agents only)' })
|
|
|
|
|
@ApiResponse({
|
|
|
|
|
status: 200,
|
|
|
|
|
description: 'Privacy preferences retrieved',
|
|
|
|
|
schema: {
|
|
|
|
|
example: {
|
|
|
|
|
privacySettings: {
|
|
|
|
|
profile_visibility: 'public',
|
|
|
|
|
contact_info: 'connections',
|
|
|
|
|
activity_status: 'public',
|
|
|
|
|
},
|
|
|
|
|
dataSettings: {
|
|
|
|
|
shareAnalytics: false,
|
|
|
|
|
personalizedAds: false,
|
|
|
|
|
thirdPartySharing: false,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
async getPrivacyPreferences(@CurrentUser('id') userId: string) {
|
|
|
|
|
return this.agentsService.getPrivacyPreferences(userId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Put('preferences/privacy')
|
|
|
|
|
@UseGuards(JwtAuthGuard, RolesGuard)
|
|
|
|
|
@Roles(UserRole.AGENT)
|
|
|
|
|
@ApiBearerAuth()
|
|
|
|
|
@ApiOperation({ summary: 'Update privacy preferences (Agents only)' })
|
|
|
|
|
@ApiResponse({ status: 200, description: 'Privacy preferences updated' })
|
|
|
|
|
async updatePrivacyPreferences(
|
|
|
|
|
@CurrentUser('id') userId: string,
|
|
|
|
|
@Body()
|
|
|
|
|
data: {
|
|
|
|
|
privacySettings?: Record<string, string>;
|
|
|
|
|
dataSettings?: Record<string, boolean>;
|
|
|
|
|
},
|
|
|
|
|
) {
|
|
|
|
|
return this.agentsService.updatePrivacyPreferences(userId, data);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-09 01:15:45 +05:30
|
|
|
// Delete account endpoint
|
|
|
|
|
|
|
|
|
|
@Delete('account')
|
|
|
|
|
@UseGuards(JwtAuthGuard, RolesGuard)
|
|
|
|
|
@Roles(UserRole.AGENT)
|
|
|
|
|
@ApiBearerAuth()
|
|
|
|
|
@ApiOperation({ summary: 'Delete agent account permanently (Agents only)' })
|
|
|
|
|
@ApiResponse({ status: 200, description: 'Account deleted successfully' })
|
|
|
|
|
@ApiResponse({ status: 404, description: 'User not found' })
|
|
|
|
|
async deleteAccount(@CurrentUser('id') userId: string) {
|
|
|
|
|
return this.agentsService.deleteAccount(userId);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-24 23:10:05 +05:30
|
|
|
// Public parameterized routes - MUST come after specific routes like profile/*
|
|
|
|
|
@Get(':id')
|
|
|
|
|
@Public()
|
2026-03-28 18:46:49 +05:30
|
|
|
@UseGuards(OptionalAuthGuard)
|
2026-01-24 23:10:05 +05:30
|
|
|
@ApiOperation({ summary: 'Get agent profile by ID' })
|
|
|
|
|
@ApiResponse({ status: 200, description: 'Agent profile retrieved successfully' })
|
|
|
|
|
@ApiResponse({ status: 404, description: 'Agent profile not found' })
|
2026-03-28 18:46:49 +05:30
|
|
|
async getAgentById(@Param('id', ParseUUIDPipe) id: string, @Req() req: any) {
|
|
|
|
|
const requestingUserId = req.user?.id || null;
|
|
|
|
|
return this.agentsService.getProfileById(id, requestingUserId);
|
2026-01-24 23:10:05 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Get(':id/field-values')
|
|
|
|
|
@Public()
|
|
|
|
|
@ApiOperation({ summary: 'Get field values for an agent profile by ID (public)' })
|
2026-01-24 21:06:08 +05:30
|
|
|
@ApiResponse({ status: 200, description: 'Field values retrieved successfully' })
|
2026-01-24 23:10:05 +05:30
|
|
|
@ApiResponse({ status: 404, description: 'Agent profile not found' })
|
|
|
|
|
async getFieldValuesByAgentId(@Param('id', ParseUUIDPipe) id: string) {
|
|
|
|
|
return this.agentsService.getFieldValuesByAgentId(id);
|
2026-01-24 21:06:08 +05:30
|
|
|
}
|
|
|
|
|
|
2026-01-11 20:59:12 +05:30
|
|
|
// Admin endpoints
|
|
|
|
|
|
|
|
|
|
@Get('admin/list')
|
|
|
|
|
@UseGuards(JwtAuthGuard, RolesGuard)
|
|
|
|
|
@Roles(UserRole.ADMIN)
|
|
|
|
|
@ApiBearerAuth()
|
|
|
|
|
@ApiOperation({ summary: 'Admin: List all agents' })
|
|
|
|
|
@ApiResponse({ status: 200, description: 'Agents retrieved successfully' })
|
|
|
|
|
async adminListAgents(@Query() dto: SearchAgentsDto) {
|
|
|
|
|
return this.agentsService.getAllAgentsAdmin(dto);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Put('admin/:id')
|
|
|
|
|
@UseGuards(JwtAuthGuard, RolesGuard)
|
|
|
|
|
@Roles(UserRole.ADMIN)
|
|
|
|
|
@ApiBearerAuth()
|
|
|
|
|
@ApiOperation({ summary: 'Admin: Update agent profile' })
|
|
|
|
|
@ApiResponse({ status: 200, description: 'Profile updated successfully' })
|
|
|
|
|
@ApiResponse({ status: 404, description: 'Profile not found' })
|
|
|
|
|
async adminUpdateProfile(
|
|
|
|
|
@Param('id', ParseUUIDPipe) id: string,
|
|
|
|
|
@Body() dto: UpdateAgentProfileDto,
|
|
|
|
|
) {
|
|
|
|
|
return this.agentsService.adminUpdateProfile(id, dto);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Delete('admin/:id')
|
|
|
|
|
@UseGuards(JwtAuthGuard, RolesGuard)
|
|
|
|
|
@Roles(UserRole.ADMIN)
|
|
|
|
|
@ApiBearerAuth()
|
|
|
|
|
@ApiOperation({ summary: 'Admin: Delete agent profile' })
|
|
|
|
|
@ApiResponse({ status: 200, description: 'Profile deleted successfully' })
|
|
|
|
|
@ApiResponse({ status: 404, description: 'Profile not found' })
|
|
|
|
|
async adminDeleteProfile(@Param('id', ParseUUIDPipe) id: string) {
|
|
|
|
|
return this.agentsService.adminDeleteProfile(id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Put('admin/:id/verify')
|
|
|
|
|
@UseGuards(JwtAuthGuard, RolesGuard)
|
|
|
|
|
@Roles(UserRole.ADMIN)
|
|
|
|
|
@ApiBearerAuth()
|
2026-01-28 13:48:14 +05:30
|
|
|
@ApiOperation({ summary: 'Admin: Update agent verification status' })
|
2026-01-11 20:59:12 +05:30
|
|
|
@ApiResponse({ status: 200, description: 'Verification status updated' })
|
|
|
|
|
@ApiResponse({ status: 404, description: 'Profile not found' })
|
|
|
|
|
async adminVerifyAgent(
|
|
|
|
|
@Param('id', ParseUUIDPipe) id: string,
|
2026-01-28 13:48:14 +05:30
|
|
|
@Body() data: { status: VerificationStatus; note?: string },
|
|
|
|
|
@CurrentUser() admin: { id: string },
|
2026-01-11 20:59:12 +05:30
|
|
|
) {
|
2026-01-28 13:48:14 +05:30
|
|
|
return this.agentsService.adminVerifyAgent(id, {
|
|
|
|
|
status: data.status,
|
|
|
|
|
note: data.note,
|
|
|
|
|
adminId: admin.id,
|
|
|
|
|
});
|
2026-01-11 20:59:12 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Put('admin/:id/featured')
|
|
|
|
|
@UseGuards(JwtAuthGuard, RolesGuard)
|
|
|
|
|
@Roles(UserRole.ADMIN)
|
|
|
|
|
@ApiBearerAuth()
|
|
|
|
|
@ApiOperation({ summary: 'Admin: Set agent as featured' })
|
|
|
|
|
@ApiResponse({ status: 200, description: 'Featured status updated' })
|
|
|
|
|
@ApiResponse({ status: 404, description: 'Profile not found' })
|
|
|
|
|
async adminSetFeatured(
|
|
|
|
|
@Param('id', ParseUUIDPipe) id: string,
|
|
|
|
|
@Body('isFeatured') isFeatured: boolean,
|
|
|
|
|
) {
|
|
|
|
|
return this.agentsService.adminSetFeatured(id, isFeatured);
|
|
|
|
|
}
|
|
|
|
|
}
|