import { Injectable, NotFoundException, Logger } from '@nestjs/common'; import { PrismaService } from '../prisma/prisma.service'; import { UpdateUserDto, ApproveUserDto } from './dto'; import { Role } from '@prisma/client'; @Injectable() export class UsersService { private readonly logger = new Logger(UsersService.name); constructor(private prisma: PrismaService) {} async findAll() { return this.prisma.user.findMany({ where: { deletedAt: null }, include: { driver: true }, orderBy: { createdAt: 'desc' }, }); } async findOne(id: string) { const user = await this.prisma.user.findFirst({ where: { id, deletedAt: null }, include: { driver: true }, }); if (!user) { throw new NotFoundException(`User with ID ${id} not found`); } return user; } async update(id: string, updateUserDto: UpdateUserDto) { const user = await this.findOne(id); this.logger.log(`Updating user ${id}: ${JSON.stringify(updateUserDto)}`); const { isAlsoDriver, ...prismaData } = updateUserDto; const effectiveRole = updateUserDto.role || user.role; // Handle role change to DRIVER: auto-create driver record if (updateUserDto.role === Role.DRIVER && !user.driver) { this.logger.log( `Creating Driver record for user ${user.email} (role change to DRIVER)`, ); await this.prisma.driver.create({ data: { name: user.name || user.email, phone: user.email, userId: user.id, }, }); } // When promoting FROM DRIVER to Admin/Coordinator, keep the driver record // (admin can explicitly uncheck the driver box later if they want) // Handle "Also a Driver" toggle (independent of role) if (isAlsoDriver === true && !user.driver) { this.logger.log( `Creating Driver record for user ${user.email} (isAlsoDriver toggled on)`, ); await this.prisma.driver.create({ data: { name: user.name || user.email, phone: user.email, userId: user.id, }, }); } else if (isAlsoDriver === false && user.driver && effectiveRole !== Role.DRIVER) { // Only allow removing driver record if user is NOT in the DRIVER role this.logger.log( `Soft-deleting Driver record for user ${user.email} (isAlsoDriver toggled off)`, ); await this.prisma.driver.update({ where: { id: user.driver.id }, data: { deletedAt: new Date() }, }); } return this.prisma.user.update({ where: { id: user.id }, data: prismaData, include: { driver: true }, }); } async approve(id: string, approveUserDto: ApproveUserDto) { const user = await this.findOne(id); this.logger.log( `${approveUserDto.isApproved ? 'Approving' : 'Denying'} user: ${user.email}`, ); return this.prisma.user.update({ where: { id: user.id }, data: { isApproved: approveUserDto.isApproved }, include: { driver: true }, }); } async remove(id: string) { const user = await this.findOne(id); this.logger.log(`Soft deleting user: ${user.email}`); return this.prisma.user.update({ where: { id: user.id }, data: { deletedAt: new Date() }, }); } async getPendingUsers() { return this.prisma.user.findMany({ where: { deletedAt: null, isApproved: false, }, orderBy: { createdAt: 'asc' }, }); } }