refactor: code efficiency improvements (Issues #9-13, #15, #17-20)

Backend:
- Extract shared hard-delete authorization utility (#9)
- Extract Prisma include constants per entity (#11)
- Fix N+1 query pattern in events findAll (#12)
- Extract shared date utility functions (#13)
- Move vehicle utilization filtering to DB query (#15)
- Add ParseBooleanPipe for query params
- Add CurrentDriver decorator + ResolveDriverInterceptor (#20)

Frontend:
- Extract shared form utilities (toDatetimeLocal) and enum labels (#17)
- Replace browser confirm() with styled ConfirmModal (#18)
- Add centralized query-keys.ts constants (#19)
- Clean up unused imports, add useMemo where needed (#19)
- Standardize filter button styling across list pages

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-08 16:07:19 +01:00
parent 806b67954e
commit f2b3f34a72
38 changed files with 1042 additions and 463 deletions

View File

@@ -0,0 +1,41 @@
/**
* Enum Display Labels
* Centralized mapping of enum values to human-readable labels
*/
export const DEPARTMENT_LABELS: Record<string, string> = {
OFFICE_OF_DEVELOPMENT: 'Office of Development',
ADMIN: 'Admin',
OTHER: 'Other',
};
export const ARRIVAL_MODE_LABELS: Record<string, string> = {
FLIGHT: 'Flight',
SELF_DRIVING: 'Self Driving',
};
export const EVENT_TYPE_LABELS: Record<string, string> = {
TRANSPORT: 'Transport',
MEETING: 'Meeting',
EVENT: 'Event',
MEAL: 'Meal',
ACCOMMODATION: 'Accommodation',
};
export const EVENT_STATUS_LABELS: Record<string, string> = {
SCHEDULED: 'Scheduled',
IN_PROGRESS: 'In Progress',
COMPLETED: 'Completed',
CANCELLED: 'Cancelled',
};
/**
* Helper function to get a label for any enum value
* Falls back to the value itself if no mapping is found
*/
export function getEnumLabel(
value: string,
labels: Record<string, string>
): string {
return labels[value] || value;
}

View File

@@ -0,0 +1,93 @@
/**
* Query key factory constants for TanStack Query
*
* This file provides typed, centralized query key management for all entities.
* Using factory functions ensures consistent keys across the application.
*
* @see https://tkdodo.eu/blog/effective-react-query-keys
*/
export const queryKeys = {
// VIPs
vips: {
all: ['vips'] as const,
detail: (id: string) => ['vip', id] as const,
forSchedule: (vipIds: string) => ['vips-for-schedule', vipIds] as const,
},
// Drivers
drivers: {
all: ['drivers'] as const,
myProfile: ['my-driver-profile'] as const,
schedule: (driverId: string, date: string) => ['driver-schedule', driverId, date] as const,
},
// Events/Schedule
events: {
all: ['events'] as const,
},
// Vehicles
vehicles: {
all: ['vehicles'] as const,
},
// Flights
flights: {
all: ['flights'] as const,
budget: ['flights', 'budget'] as const,
},
// Users
users: {
all: ['users'] as const,
},
// GPS/Location Tracking
gps: {
status: ['gps', 'status'] as const,
settings: ['gps', 'settings'] as const,
devices: ['gps', 'devices'] as const,
deviceQr: (driverId: string) => ['gps', 'devices', driverId, 'qr'] as const,
locations: {
all: ['gps', 'locations'] as const,
detail: (driverId: string) => ['gps', 'locations', driverId] as const,
},
stats: (driverId: string, from?: string, to?: string) =>
['gps', 'stats', driverId, from, to] as const,
me: {
status: ['gps', 'me'] as const,
stats: (from?: string, to?: string) => ['gps', 'me', 'stats', from, to] as const,
location: ['gps', 'me', 'location'] as const,
},
traccar: {
status: ['gps', 'traccar', 'status'] as const,
adminUrl: ['gps', 'traccar', 'admin-url'] as const,
},
},
// Settings
settings: {
pdf: ['settings', 'pdf'] as const,
timezone: ['settings', 'timezone'] as const,
},
// Signal Messages
signal: {
messages: (driverId: string) => ['signal-messages', driverId] as const,
unreadCounts: ['signal-unread-counts'] as const,
driverResponses: (eventIds: string) => ['signal-driver-responses', eventIds] as const,
status: ['signal-status'] as const,
messageStats: ['signal-message-stats'] as const,
},
// Admin
admin: {
stats: ['admin-stats'] as const,
},
// Features
features: {
all: ['features'] as const,
},
} as const;

View File

@@ -35,3 +35,18 @@ export function formatTime(date: string | Date, timeZone?: string): string {
...(timeZone && { timeZone }),
});
}
/**
* Convert ISO datetime string to datetime-local input format (YYYY-MM-DDTHH:mm)
* Used for populating datetime-local inputs in forms
*/
export function toDatetimeLocal(isoString: string | null | undefined): string {
if (!isoString) return '';
const date = new Date(isoString);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
return `${year}-${month}-${day}T${hours}:${minutes}`;
}