Skip to content

Commit e95e92a

Browse files
committed
Merge driver and admin into employee; fix error with fields not persisting in edit modal
1 parent b5a75a8 commit e95e92a

37 files changed

Lines changed: 9253 additions & 14305 deletions

File tree

frontend/src/components/EmployeeCards/EmployeeCards.tsx

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ import { useNavigate } from 'react-router-dom';
22
import Card, { CardInfo } from '../Card/Card';
33
import styles from './employeecards.module.css';
44
import { phone, wheel, user } from '../../icons/userInfo/index';
5-
import { AdminType } from '@carriage-web/shared/types/admin';
6-
import { DriverType } from '@carriage-web/shared/types/driver';
5+
import { EmployeeType } from '@carriage-web/shared/types/employee';
76

87
const formatPhone = (phoneNumber: string | undefined) => {
98
if (phoneNumber !== undefined) {
@@ -17,34 +16,19 @@ const formatPhone = (phoneNumber: string | undefined) => {
1716
}
1817
};
1918

20-
type Employee = AdminType | DriverType;
21-
22-
function isAdmin(employee: Employee): employee is AdminType {
23-
return 'isDriver' in employee;
24-
}
25-
26-
function isDriver(employee: Employee): employee is DriverType {
27-
return 'availability' in employee && !('isDriver' in employee);
28-
}
29-
3019
type EmployeeCardProps = {
3120
id: string;
32-
employee: Employee;
21+
employee: EmployeeType;
3322
};
3423

3524
const EmployeeCard = ({ id, employee }: EmployeeCardProps) => {
3625
const navigate = useNavigate();
3726
const netId = employee.email.split('@')[0];
3827
const fmtPhone = formatPhone(employee.phoneNumber);
3928

40-
// Determine if employee is admin, driver, or both
41-
const adminEmployee = isAdmin(employee);
42-
const driverEmployee = isDriver(employee);
43-
const isBoth = adminEmployee && employee.isDriver;
44-
4529
const roles = (): string => {
46-
if (isBoth) return 'Admin • Driver';
47-
if (adminEmployee) return 'Admin';
30+
if (employee.isAdmin && employee.isDriver) return 'Admin • Driver';
31+
if (employee.isAdmin) return 'Admin';
4832
return 'Driver';
4933
};
5034

@@ -68,8 +52,8 @@ const EmployeeCard = ({ id, employee }: EmployeeCardProps) => {
6852
<p>{fmtPhone}</p>
6953
</CardInfo>
7054
<CardInfo
71-
icon={adminEmployee ? user : wheel}
72-
alt={adminEmployee ? 'admin' : 'wheel'}
55+
icon={employee.isAdmin ? user : wheel}
56+
alt={employee.isAdmin ? 'admin' : 'wheel'}
7357
>
7458
<p>{roles()}</p>
7559
</CardInfo>
@@ -79,7 +63,7 @@ const EmployeeCard = ({ id, employee }: EmployeeCardProps) => {
7963
};
8064

8165
type EmployeeCardsProps = {
82-
employees: Employee[];
66+
employees: EmployeeType[];
8367
};
8468

8569
const EmployeeCards = ({ employees }: EmployeeCardsProps) => {

frontend/src/components/EmployeeModal/EmployeeModal.tsx

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ import { useEmployees } from '../../context/EmployeesContext';
1313
import { useToast, ToastStatus } from '../../context/toastContext';
1414
import axios from '../../util/axios';
1515
import { extractNetIdFromEmail } from 'util/userUtils';
16+
import { EmployeeType } from '@carriage-web/shared/types/employee';
1617

1718
type AdminData = {
18-
type: string[];
19+
adminRoles: string[];
1920
isDriver: boolean;
2021
};
2122

@@ -37,23 +38,22 @@ type EmployeeEntity = {
3738
photoLink?: string;
3839
};
3940

40-
// both for formating to current api data expections
41-
function extractAdminData(employeeData: EmployeeEntity) {
41+
// both for formatting to current api data expectations
42+
function extractAdminData(employeeData: EmployeeEntity): Omit<EmployeeType, 'id'> {
4243
return {
4344
firstName: employeeData.firstName,
4445
lastName: employeeData.lastName,
45-
type: (employeeData.admin?.type || []) as (
46-
| 'sds-admin'
47-
| 'redrunner-admin'
48-
)[],
46+
adminRoles: employeeData.admin?.adminRoles || [],
47+
isAdmin: true,
4948
isDriver: employeeData.admin?.isDriver || false,
5049
phoneNumber: employeeData.phoneNumber,
5150
email: employeeData.email,
5251
photoLink: employeeData.photoLink,
52+
availability: employeeData.driver?.availability || [],
5353
};
5454
}
5555

56-
function extractDriverData(employeeData: EmployeeEntity) {
56+
function extractDriverData(employeeData: EmployeeEntity): Partial<EmployeeType> {
5757
return {
5858
firstName: employeeData.firstName,
5959
lastName: employeeData.lastName,
@@ -62,6 +62,7 @@ function extractDriverData(employeeData: EmployeeEntity) {
6262
joinDate: employeeData.driver?.startDate,
6363
email: employeeData.email,
6464
photoLink: employeeData.photoLink,
65+
isDriver: true,
6566
};
6667
}
6768

@@ -93,13 +94,12 @@ const EmployeeModal = ({
9394
// Initialize form and roles when modal opens or existing employee changes
9495
React.useEffect(() => {
9596
if (existingEmployee && isOpen) {
96-
// Initialize roles
97+
// Initialize roles, normalizing Prisma enum values (SDS_ADMIN → sds-admin)
98+
const normalizeRole = (r: string) =>
99+
r.toLowerCase().replace(/_/g, '-');
97100
const roles: string[] = [];
98-
if (existingEmployee.admin) {
99-
// Add admin roles
100-
if (existingEmployee.admin.type) {
101-
roles.push(...existingEmployee.admin.type);
102-
}
101+
if (existingEmployee.admin?.adminRoles) {
102+
roles.push(...existingEmployee.admin.adminRoles.map(normalizeRole));
103103
}
104104
if (existingEmployee.driver) {
105105
roles.push('driver');
@@ -131,8 +131,9 @@ const EmployeeModal = ({
131131

132132
const closeModal = () => {
133133
methods.clearErrors();
134-
setImageBase64(''); // Reset image state
135-
setIsUploadingImage(false); // Reset upload state
134+
setImageBase64('');
135+
setIsUploadingImage(false);
136+
setSelectedRole([]);
136137
setIsOpen(false);
137138
};
138139

@@ -178,7 +179,7 @@ const EmployeeModal = ({
178179
switch (endpoint) {
179180
case '/api/drivers':
180181
// Use optimistic create from context
181-
await createDriver(extractDriverData(employeeData));
182+
await createDriver(extractDriverData(employeeData) as Omit<EmployeeType, 'id'>);
182183
res = employeeData; // The context will handle server response and ID assignment
183184
break;
184185
case '/api/admins':
@@ -330,7 +331,7 @@ const EmployeeModal = ({
330331

331332
if (hasAdmin) {
332333
admin_data = {
333-
type: selectedRoles.filter((role) => role !== 'driver'),
334+
adminRoles: selectedRoles.filter((role) => role !== 'driver'),
334335
isDriver: hasDriver,
335336
};
336337
}
@@ -436,8 +437,13 @@ const EmployeeModal = ({
436437
phone={existingEmployee?.phoneNumber}
437438
/>
438439

440+
<RoleSelector
441+
selectedRoles={selectedRoles}
442+
setSelectedRoles={setSelectedRole}
443+
/>
444+
439445
{(selectedRoles.includes('driver') ||
440-
existingEmployee?.driver?.availability) && (
446+
existingEmployee?.driver != null) && (
441447
<>
442448
<StartDate existingDate={existingEmployee?.driver?.startDate} />
443449
<WorkingHours
@@ -447,11 +453,6 @@ const EmployeeModal = ({
447453
</>
448454
)}
449455

450-
<RoleSelector
451-
selectedRoles={selectedRoles}
452-
setSelectedRoles={setSelectedRole}
453-
/>
454-
455456
<Button className={styles.submit} type="submit">
456457
{existingEmployee ? 'Save' : 'Add'}
457458
</Button>

frontend/src/components/UserDetail/ActionsCard.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,19 +53,21 @@ const ActionsCard: React.FC<ActionsCardProps> = ({
5353
netId: (employee as any).netId || '',
5454
email: employee.email,
5555
phoneNumber: employee.phoneNumber.replaceAll('-', ''),
56-
...(employee.availability || employee.startDate
56+
...(employee.isDriver
5757
? {
5858
driver: {
5959
availability: (employee.availability || []) as any[],
60-
startDate: employee.startDate || '',
60+
startDate: employee.startDate
61+
? new Date(employee.startDate).toISOString().split('T')[0]
62+
: '',
6163
},
6264
}
6365
: {}),
64-
...(employee.type
66+
...(employee.isAdmin
6567
? {
6668
admin: {
67-
isDriver: employee.isDriver || false,
68-
type: employee.type || [],
69+
isDriver: employee.isDriver,
70+
adminRoles: employee.adminRoles || [],
6971
},
7072
}
7173
: {}),
@@ -116,7 +118,7 @@ const ActionsCard: React.FC<ActionsCardProps> = ({
116118
const getUserRole = () => {
117119
if (userType === 'employee') {
118120
const employee = user as Employee;
119-
if (employee.isDriver && employee.type && employee.type.length > 0) {
121+
if (employee.isDriver && employee.isAdmin) {
120122
return 'both';
121123
} else if (employee.isDriver) {
122124
return 'driver';

frontend/src/components/UserDetail/UserInfoCard.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,8 @@ interface UserInfoCardProps {
2929
const UserInfoCard: React.FC<UserInfoCardProps> = ({ user, userType }) => {
3030
const getEmployeeRole = (employee: Employee) => {
3131
const roles: string[] = [];
32-
if (employee.isDriver) {
33-
roles.push('driver');
34-
}
35-
if (employee.type && employee.type.length > 0) {
36-
roles.push(...employee.type);
37-
}
32+
if (employee.isDriver) roles.push('driver');
33+
if (employee.isAdmin) roles.push(...(employee.adminRoles.length > 0 ? employee.adminRoles.map((r) => r.toLowerCase().replace('_', '-')) : ['admin']));
3834
return roles.length > 0 ? roles.join(' • ') : 'N/A';
3935
};
4036

0 commit comments

Comments
 (0)