agent and category Dto creation
This commit is contained in:
509
src/agents/agents.service.ts
Normal file
509
src/agents/agents.service.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user