agent and category Dto creation

This commit is contained in:
pradeepkumar
2026-01-11 20:59:12 +05:30
parent 14ca59f02c
commit c72be7d2ac
35 changed files with 3665 additions and 317 deletions

View File

@@ -0,0 +1,509 @@
import {
Injectable,
NotFoundException,
ForbiddenException,
ConflictException,
} from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import {
CreateAgentProfileDto,
UpdateAgentProfileDto,
SearchAgentsDto,
} from './dto';
import { Prisma } from '@prisma/client';
function generateSlug(firstName: string, lastName: string): string {
const base = `${firstName}-${lastName}`
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-|-$/g, '');
const uniqueSuffix = Math.random().toString(36).substring(2, 8);
return `${base}-${uniqueSuffix}`;
}
@Injectable()
export class AgentsService {
constructor(private prisma: PrismaService) {}
async createProfile(userId: string, dto: CreateAgentProfileDto) {
// Check if user already has an agent profile
const existingProfile = await this.prisma.agentProfile.findUnique({
where: { userId },
});
if (existingProfile) {
throw new ConflictException('User already has an agent profile');
}
const { specializationIds, ...profileData } = dto;
const slug = generateSlug(dto.firstName, dto.lastName);
const profile = await this.prisma.agentProfile.create({
data: {
...profileData,
userId,
slug,
specializations: specializationIds?.length
? {
create: specializationIds.map((specId) => ({
specializationId: specId,
})),
}
: undefined,
},
include: {
user: {
select: {
id: true,
email: true,
avatar: true,
},
},
specializations: {
include: {
specialization: {
include: {
category: true,
},
},
},
},
},
});
return profile;
}
async getProfile(userId: string) {
const profile = await this.prisma.agentProfile.findUnique({
where: { userId },
include: {
user: {
select: {
id: true,
email: true,
avatar: true,
},
},
specializations: {
include: {
specialization: {
include: {
category: true,
},
},
},
},
verificationRequests: {
orderBy: { createdAt: 'desc' },
take: 5,
},
},
});
if (!profile) {
throw new NotFoundException('Agent profile not found');
}
return profile;
}
async getProfileById(profileId: string) {
const profile = await this.prisma.agentProfile.findUnique({
where: { id: profileId },
include: {
user: {
select: {
id: true,
email: true,
avatar: true,
},
},
specializations: {
include: {
specialization: {
include: {
category: true,
},
},
},
},
},
});
if (!profile) {
throw new NotFoundException('Agent profile not found');
}
return profile;
}
async updateProfile(userId: string, dto: UpdateAgentProfileDto) {
const profile = await this.prisma.agentProfile.findUnique({
where: { userId },
});
if (!profile) {
throw new NotFoundException('Agent profile not found');
}
const { specializationIds, ...profileData } = dto;
// If specializationIds is provided, update the specializations
if (specializationIds !== undefined) {
// Delete existing specializations
await this.prisma.agentSpecialization.deleteMany({
where: { agentProfileId: profile.id },
});
// Create new specializations
if (specializationIds.length > 0) {
await this.prisma.agentSpecialization.createMany({
data: specializationIds.map((specId) => ({
agentProfileId: profile.id,
specializationId: specId,
})),
});
}
}
const updatedProfile = await this.prisma.agentProfile.update({
where: { userId },
data: profileData,
include: {
user: {
select: {
id: true,
email: true,
avatar: true,
},
},
specializations: {
include: {
specialization: {
include: {
category: true,
},
},
},
},
},
});
return updatedProfile;
}
async searchAgents(dto: SearchAgentsDto) {
const {
search,
city,
state,
country,
categoryId,
specializationIds,
isVerified,
page = 1,
limit = 10,
sortBy = 'createdAt',
sortOrder = 'desc',
} = dto;
const skip = (page - 1) * limit;
// Build where clause
const where: Prisma.AgentProfileWhereInput = {};
if (search) {
where.OR = [
{ firstName: { contains: search, mode: 'insensitive' } },
{ lastName: { contains: search, mode: 'insensitive' } },
{ bio: { contains: search, mode: 'insensitive' } },
{ headline: { contains: search, mode: 'insensitive' } },
{ companyName: { contains: search, mode: 'insensitive' } },
];
}
if (city) {
where.city = { contains: city, mode: 'insensitive' };
}
if (state) {
where.state = { contains: state, mode: 'insensitive' };
}
if (country) {
where.country = { contains: country, mode: 'insensitive' };
}
if (isVerified !== undefined) {
where.isVerified = isVerified;
}
// Filter by category
if (categoryId) {
where.specializations = {
some: {
specialization: {
categoryId,
},
},
};
}
// Filter by specializations
if (specializationIds?.length) {
where.specializations = {
some: {
specializationId: { in: specializationIds },
},
};
}
// Build orderBy
const orderBy: Prisma.AgentProfileOrderByWithRelationInput = {};
if (sortBy === 'averageRating') {
orderBy.averageRating = sortOrder;
} else if (sortBy === 'totalReviews') {
orderBy.totalReviews = sortOrder;
} else if (sortBy === 'firstName') {
orderBy.firstName = sortOrder;
} else {
orderBy.createdAt = sortOrder;
}
const [agents, total] = await Promise.all([
this.prisma.agentProfile.findMany({
where,
skip,
take: limit,
orderBy,
include: {
user: {
select: {
id: true,
email: true,
avatar: true,
},
},
specializations: {
include: {
specialization: {
include: {
category: true,
},
},
},
},
},
}),
this.prisma.agentProfile.count({ where }),
]);
return {
data: agents,
meta: {
total,
page,
limit,
totalPages: Math.ceil(total / limit),
},
};
}
async getFeaturedAgents(limit = 10) {
const agents = await this.prisma.agentProfile.findMany({
where: {
isVerified: true,
isFeatured: true,
},
take: limit,
orderBy: [{ averageRating: 'desc' }, { totalReviews: 'desc' }],
include: {
user: {
select: {
id: true,
email: true,
avatar: true,
},
},
specializations: {
include: {
specialization: {
include: {
category: true,
},
},
},
},
},
});
return agents;
}
async getTopRatedAgents(limit = 10) {
const agents = await this.prisma.agentProfile.findMany({
where: {
isVerified: true,
totalReviews: { gte: 5 },
},
take: limit,
orderBy: [{ averageRating: 'desc' }, { totalReviews: 'desc' }],
include: {
user: {
select: {
id: true,
email: true,
avatar: true,
},
},
specializations: {
include: {
specialization: {
include: {
category: true,
},
},
},
},
},
});
return agents;
}
// Admin methods
async adminUpdateProfile(profileId: string, dto: UpdateAgentProfileDto) {
const profile = await this.prisma.agentProfile.findUnique({
where: { id: profileId },
});
if (!profile) {
throw new NotFoundException('Agent profile not found');
}
const { specializationIds, ...profileData } = dto;
if (specializationIds !== undefined) {
await this.prisma.agentSpecialization.deleteMany({
where: { agentProfileId: profileId },
});
if (specializationIds.length > 0) {
await this.prisma.agentSpecialization.createMany({
data: specializationIds.map((specId) => ({
agentProfileId: profileId,
specializationId: specId,
})),
});
}
}
const updatedProfile = await this.prisma.agentProfile.update({
where: { id: profileId },
data: profileData,
include: {
user: {
select: {
id: true,
email: true,
avatar: true,
},
},
specializations: {
include: {
specialization: {
include: {
category: true,
},
},
},
},
},
});
return updatedProfile;
}
async adminDeleteProfile(profileId: string) {
const profile = await this.prisma.agentProfile.findUnique({
where: { id: profileId },
});
if (!profile) {
throw new NotFoundException('Agent profile not found');
}
// Delete related records first
await this.prisma.agentSpecialization.deleteMany({
where: { agentProfileId: profileId },
});
await this.prisma.verificationRequest.deleteMany({
where: { agentProfileId: profileId },
});
await this.prisma.agentProfile.delete({
where: { id: profileId },
});
return { message: 'Agent profile deleted successfully' };
}
async adminVerifyAgent(profileId: string, isVerified: boolean) {
const profile = await this.prisma.agentProfile.findUnique({
where: { id: profileId },
});
if (!profile) {
throw new NotFoundException('Agent profile not found');
}
const updatedProfile = await this.prisma.agentProfile.update({
where: { id: profileId },
data: { isVerified },
include: {
user: {
select: {
id: true,
email: true,
avatar: true,
},
},
},
});
return updatedProfile;
}
async adminSetFeatured(profileId: string, isFeatured: boolean) {
const profile = await this.prisma.agentProfile.findUnique({
where: { id: profileId },
});
if (!profile) {
throw new NotFoundException('Agent profile not found');
}
const updatedProfile = await this.prisma.agentProfile.update({
where: { id: profileId },
data: { isFeatured },
include: {
user: {
select: {
id: true,
email: true,
avatar: true,
},
},
},
});
return updatedProfile;
}
async getAllAgentsAdmin(dto: SearchAgentsDto) {
// Same as searchAgents but returns all data for admin
return this.searchAgents(dto);
}
}