feat: Synchronize agent phone numbers between profile and field values, and add optional service areas to agent profile DTO.

This commit is contained in:
pradeepkumar
2026-02-09 02:04:12 +05:30
parent bbbd83084a
commit 6bc0b41e1f
2 changed files with 85 additions and 3 deletions

View File

@@ -112,9 +112,16 @@ export class AgentsService {
throw new NotFoundException('Agent profile not found'); throw new NotFoundException('Agent profile not found');
} }
// Filter out fields that don't exist in the database schema
// serviceAreas is accepted by DTO but stored in field values, not direct column
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { serviceAreas, ...profileData } = dto as UpdateAgentProfileDto & {
serviceAreas?: string[];
};
const updatedProfile = await this.prisma.agentProfile.update({ const updatedProfile = await this.prisma.agentProfile.update({
where: { userId }, where: { userId },
data: dto, data: profileData,
include: { include: {
user: { user: {
select: { select: {
@@ -127,9 +134,50 @@ export class AgentsService {
}, },
}); });
// Sync phone to field values if phone was updated
// This keeps AgentProfile.phone and AgentProfileFieldValue in sync
if (dto.phone !== undefined) {
await this.syncPhoneToFieldValues(profile.id, dto.phone);
}
return updatedProfile; return updatedProfile;
} }
/**
* Sync phone from AgentProfile to AgentProfileFieldValue
* This ensures both storage locations have the same phone value
*/
private async syncPhoneToFieldValues(
agentProfileId: string,
phone: string | null,
) {
// Find any phone-related field definitions
const phoneField = await this.prisma.profileField.findFirst({
where: {
slug: { in: ['phone', 'phone_number', 'cell_number', 'office_number'] },
},
});
if (phoneField) {
await this.prisma.agentProfileFieldValue.upsert({
where: {
agentProfileId_fieldId: {
agentProfileId,
fieldId: phoneField.id,
},
},
create: {
agentProfileId,
fieldId: phoneField.id,
textValue: phone,
},
update: {
textValue: phone,
},
});
}
}
async searchAgents(dto: SearchAgentsDto) { async searchAgents(dto: SearchAgentsDto) {
const { const {
search, search,
@@ -574,6 +622,26 @@ export class AgentsService {
results.push(result); results.push(result);
} }
// Sync phone from field values to AgentProfile.phone
// This keeps both storage locations in sync
const phoneSlugs = ['phone', 'phone_number', 'cell_number', 'office_number'];
const phoneFieldValue = dto.fieldValues.find((fv) =>
phoneSlugs.includes(fv.fieldSlug),
);
if (phoneFieldValue !== undefined) {
const phoneValue = phoneFieldValue.value;
await this.prisma.agentProfile.update({
where: { id: profile.id },
data: {
phone:
phoneValue === '' || phoneValue === null
? null
: String(phoneValue),
},
});
}
return { return {
message: 'Field values saved successfully', message: 'Field values saved successfully',
savedCount: results.length, savedCount: results.length,

View File

@@ -1,4 +1,5 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { Transform } from 'class-transformer';
import { import {
IsString, IsString,
IsOptional, IsOptional,
@@ -6,10 +7,12 @@ import {
IsUrl, IsUrl,
IsUUID, IsUUID,
IsBoolean, IsBoolean,
IsArray,
MinLength, MinLength,
MaxLength, MaxLength,
Min, Min,
Max, Max,
ValidateIf,
} from 'class-validator'; } from 'class-validator';
export class CreateAgentProfileDto { export class CreateAgentProfileDto {
@@ -33,11 +36,13 @@ export class CreateAgentProfileDto {
@MaxLength(100) @MaxLength(100)
lastName: string; lastName: string;
@ApiPropertyOptional({ example: '+1234567890' }) @ApiPropertyOptional({ example: '+1234567890', nullable: true })
@IsOptional() @IsOptional()
@ValidateIf((o) => o.phone !== null)
@IsString() @IsString()
@MaxLength(20) @MaxLength(20)
phone?: string; @Transform(({ value }) => (value === '' ? null : value))
phone?: string | null;
@ApiPropertyOptional({ example: 'Experienced real estate agent...' }) @ApiPropertyOptional({ example: 'Experienced real estate agent...' })
@IsOptional() @IsOptional()
@@ -140,4 +145,13 @@ export class CreateAgentProfileDto {
@IsOptional() @IsOptional()
@IsBoolean() @IsBoolean()
isAvailable?: boolean; isAvailable?: boolean;
@ApiPropertyOptional({
example: ['Los Angeles', 'San Francisco'],
description: 'Service areas the agent covers',
})
@IsOptional()
@IsArray()
@IsString({ each: true })
serviceAreas?: string[];
} }