feat: allow admins and coordinators to also be drivers
Add a "Driver" checkbox column to the User Management page. Checking it creates a linked Driver record so the user appears in the drivers list, can be assigned events, and enrolled for GPS tracking — without changing their primary role. The DRIVER role checkbox is auto-checked and disabled since being a driver is inherent to that role. Promoting a user from DRIVER to Admin/Coordinator preserves their driver record. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { IsString, IsEnum, IsOptional } from 'class-validator';
|
||||
import { IsString, IsEnum, IsOptional, IsBoolean } from 'class-validator';
|
||||
import { Role } from '@prisma/client';
|
||||
|
||||
export class UpdateUserDto {
|
||||
@@ -9,4 +9,8 @@ export class UpdateUserDto {
|
||||
@IsEnum(Role)
|
||||
@IsOptional()
|
||||
role?: Role;
|
||||
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
isAlsoDriver?: boolean;
|
||||
}
|
||||
|
||||
@@ -35,36 +35,52 @@ export class UsersService {
|
||||
|
||||
this.logger.log(`Updating user ${id}: ${JSON.stringify(updateUserDto)}`);
|
||||
|
||||
// Handle role change and Driver record synchronization
|
||||
if (updateUserDto.role && updateUserDto.role !== user.role) {
|
||||
// If changing TO DRIVER role, create a Driver record if one doesn't exist
|
||||
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, // Use email as placeholder for phone
|
||||
userId: user.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
const { isAlsoDriver, ...prismaData } = updateUserDto;
|
||||
const effectiveRole = updateUserDto.role || user.role;
|
||||
|
||||
// If changing FROM DRIVER role to something else, remove the Driver record
|
||||
if (user.role === Role.DRIVER && updateUserDto.role !== Role.DRIVER && user.driver) {
|
||||
this.logger.log(
|
||||
`Removing Driver record for user ${user.email} (role change from DRIVER to ${updateUserDto.role})`,
|
||||
);
|
||||
await this.prisma.driver.delete({
|
||||
where: { id: user.driver.id },
|
||||
});
|
||||
}
|
||||
// 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: updateUserDto,
|
||||
data: prismaData,
|
||||
include: { driver: true },
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user