2026-01-26 23:12:22 +05:30
|
|
|
import { Injectable, BadRequestException, NotFoundException } from '@nestjs/common';
|
2025-12-22 13:26:39 +05:30
|
|
|
import { UserStatus, UserRole, Prisma } from '@prisma/client';
|
2025-12-20 19:22:30 +05:30
|
|
|
import { PrismaService } from '../prisma/prisma.service';
|
|
|
|
|
|
2025-12-22 13:26:39 +05:30
|
|
|
type UserWithProfiles = Prisma.UserGetPayload<{
|
2026-01-26 23:12:22 +05:30
|
|
|
include: { userProfile: true; agentProfile: { include: { agentType: true } } };
|
2025-12-20 19:22:30 +05:30
|
|
|
}>;
|
|
|
|
|
|
|
|
|
|
@Injectable()
|
|
|
|
|
export class UsersService {
|
|
|
|
|
constructor(private readonly prisma: PrismaService) {}
|
|
|
|
|
|
2025-12-22 13:26:39 +05:30
|
|
|
async findAll(page = 1, limit = 10, role?: UserRole) {
|
2025-12-20 19:22:30 +05:30
|
|
|
const skip = (page - 1) * limit;
|
|
|
|
|
|
2025-12-22 13:26:39 +05:30
|
|
|
// Build where clause for optional role filter
|
|
|
|
|
const where: Prisma.UserWhereInput = role ? { role } : {};
|
|
|
|
|
|
2025-12-20 19:22:30 +05:30
|
|
|
const [users, total] = await Promise.all([
|
|
|
|
|
this.prisma.user.findMany({
|
2025-12-22 13:26:39 +05:30
|
|
|
where,
|
2025-12-20 19:22:30 +05:30
|
|
|
skip,
|
|
|
|
|
take: limit,
|
|
|
|
|
orderBy: { createdAt: 'desc' },
|
|
|
|
|
include: {
|
|
|
|
|
userProfile: true,
|
2026-01-26 23:12:22 +05:30
|
|
|
agentProfile: {
|
|
|
|
|
include: {
|
|
|
|
|
agentType: true,
|
|
|
|
|
},
|
|
|
|
|
},
|
2025-12-20 19:22:30 +05:30
|
|
|
},
|
2025-12-22 13:26:39 +05:30
|
|
|
}) as Promise<UserWithProfiles[]>,
|
|
|
|
|
this.prisma.user.count({ where }),
|
2025-12-20 19:22:30 +05:30
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
return {
|
2025-12-22 13:26:39 +05:30
|
|
|
users: users.map((user) => {
|
|
|
|
|
// Get the appropriate profile based on role
|
|
|
|
|
const profile = user.role === UserRole.AGENT ? user.agentProfile : user.userProfile;
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
id: user.id,
|
|
|
|
|
email: user.email,
|
|
|
|
|
role: user.role,
|
|
|
|
|
status: user.status,
|
|
|
|
|
emailVerified: user.emailVerified,
|
|
|
|
|
authProvider: user.authProvider,
|
|
|
|
|
createdAt: user.createdAt,
|
|
|
|
|
lastLoginAt: user.lastLoginAt,
|
|
|
|
|
profile: profile
|
|
|
|
|
? {
|
|
|
|
|
firstName: profile.firstName,
|
|
|
|
|
lastName: profile.lastName,
|
|
|
|
|
avatar: profile.avatar,
|
|
|
|
|
phone: profile.phone,
|
|
|
|
|
city: profile.city,
|
|
|
|
|
state: profile.state,
|
|
|
|
|
country: profile.country,
|
|
|
|
|
}
|
|
|
|
|
: null,
|
|
|
|
|
};
|
|
|
|
|
}),
|
2025-12-20 19:22:30 +05:30
|
|
|
total,
|
|
|
|
|
page,
|
|
|
|
|
limit,
|
|
|
|
|
totalPages: Math.ceil(total / limit),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async findOne(id: string) {
|
|
|
|
|
const user = (await this.prisma.user.findUnique({
|
|
|
|
|
where: { id },
|
|
|
|
|
include: {
|
|
|
|
|
userProfile: true,
|
2026-01-26 23:12:22 +05:30
|
|
|
agentProfile: {
|
|
|
|
|
include: {
|
|
|
|
|
agentType: true,
|
|
|
|
|
},
|
|
|
|
|
},
|
2025-12-20 19:22:30 +05:30
|
|
|
},
|
2025-12-22 13:26:39 +05:30
|
|
|
})) as UserWithProfiles | null;
|
2025-12-20 19:22:30 +05:30
|
|
|
|
|
|
|
|
if (!user) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-26 23:12:22 +05:30
|
|
|
// Base user data
|
|
|
|
|
const baseData = {
|
2025-12-20 19:22:30 +05:30
|
|
|
id: user.id,
|
|
|
|
|
email: user.email,
|
|
|
|
|
role: user.role,
|
|
|
|
|
status: user.status,
|
|
|
|
|
emailVerified: user.emailVerified,
|
2026-01-26 23:12:22 +05:30
|
|
|
emailVerifiedAt: user.emailVerifiedAt,
|
2025-12-20 19:22:30 +05:30
|
|
|
authProvider: user.authProvider,
|
|
|
|
|
createdAt: user.createdAt,
|
|
|
|
|
lastLoginAt: user.lastLoginAt,
|
2026-01-26 23:12:22 +05:30
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// For agents, return full agent profile
|
|
|
|
|
if (user.role === UserRole.AGENT && user.agentProfile) {
|
|
|
|
|
return {
|
|
|
|
|
...baseData,
|
|
|
|
|
profile: {
|
|
|
|
|
firstName: user.agentProfile.firstName,
|
|
|
|
|
lastName: user.agentProfile.lastName,
|
|
|
|
|
avatar: user.agentProfile.avatar,
|
|
|
|
|
phone: user.agentProfile.phone,
|
|
|
|
|
city: user.agentProfile.city,
|
|
|
|
|
state: user.agentProfile.state,
|
|
|
|
|
country: user.agentProfile.country,
|
|
|
|
|
},
|
|
|
|
|
agentProfile: {
|
|
|
|
|
id: user.agentProfile.id,
|
|
|
|
|
slug: user.agentProfile.slug,
|
|
|
|
|
bio: user.agentProfile.bio,
|
|
|
|
|
headline: user.agentProfile.headline,
|
|
|
|
|
companyName: user.agentProfile.companyName,
|
|
|
|
|
licenseNumber: user.agentProfile.licenseNumber,
|
|
|
|
|
yearsOfExperience: user.agentProfile.yearsOfExperience,
|
|
|
|
|
isProfileComplete: user.agentProfile.isProfileComplete,
|
|
|
|
|
profileCompleteness: user.agentProfile.profileCompleteness,
|
|
|
|
|
agentTypeId: user.agentProfile.agentTypeId,
|
|
|
|
|
agentType: user.agentProfile.agentType,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// For regular users
|
|
|
|
|
return {
|
|
|
|
|
...baseData,
|
|
|
|
|
profile: user.userProfile
|
2025-12-22 13:26:39 +05:30
|
|
|
? {
|
2026-01-26 23:12:22 +05:30
|
|
|
firstName: user.userProfile.firstName,
|
|
|
|
|
lastName: user.userProfile.lastName,
|
|
|
|
|
avatar: user.userProfile.avatar,
|
|
|
|
|
phone: user.userProfile.phone,
|
|
|
|
|
city: user.userProfile.city,
|
|
|
|
|
state: user.userProfile.state,
|
|
|
|
|
country: user.userProfile.country,
|
2025-12-22 13:26:39 +05:30
|
|
|
}
|
|
|
|
|
: null,
|
2025-12-20 19:22:30 +05:30
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async updateStatus(id: string, status: UserStatus) {
|
|
|
|
|
return this.prisma.user.update({
|
|
|
|
|
where: { id },
|
|
|
|
|
data: { status },
|
|
|
|
|
});
|
|
|
|
|
}
|
2026-01-26 23:12:22 +05:30
|
|
|
|
|
|
|
|
async updateAgentType(userId: string, agentTypeId: string) {
|
|
|
|
|
// Get user to verify they are an agent
|
|
|
|
|
const user = await this.prisma.user.findUnique({
|
|
|
|
|
where: { id: userId },
|
|
|
|
|
include: { agentProfile: true },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!user) {
|
|
|
|
|
throw new NotFoundException('User not found');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (user.role !== UserRole.AGENT) {
|
|
|
|
|
throw new BadRequestException('User is not an agent');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!user.agentProfile) {
|
|
|
|
|
throw new NotFoundException('Agent profile not found');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verify agent type exists
|
|
|
|
|
const agentType = await this.prisma.agentType.findUnique({
|
|
|
|
|
where: { id: agentTypeId },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!agentType) {
|
|
|
|
|
throw new BadRequestException('Invalid agent type');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update agent profile with new agent type
|
|
|
|
|
const updatedProfile = await this.prisma.agentProfile.update({
|
|
|
|
|
where: { id: user.agentProfile.id },
|
|
|
|
|
data: { agentTypeId },
|
|
|
|
|
include: { agentType: true },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
id: user.id,
|
|
|
|
|
agentTypeId: updatedProfile.agentTypeId,
|
|
|
|
|
agentType: updatedProfile.agentType,
|
|
|
|
|
message: 'Agent type updated successfully',
|
|
|
|
|
};
|
|
|
|
|
}
|
2025-12-20 19:22:30 +05:30
|
|
|
}
|