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

@@ -1,5 +1,6 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { api } from '../lib/api';
import { queryKeys } from '../lib/query-keys';
export interface SignalMessage {
id: string;
@@ -19,7 +20,7 @@ export interface UnreadCounts {
*/
export function useDriverMessages(driverId: string | null, enabled = true) {
return useQuery({
queryKey: ['signal-messages', driverId],
queryKey: driverId ? queryKeys.signal.messages(driverId) : ['signal-messages', null],
queryFn: async () => {
if (!driverId) return [];
const { data } = await api.get<SignalMessage[]>(`/signal/messages/driver/${driverId}`);
@@ -35,7 +36,7 @@ export function useDriverMessages(driverId: string | null, enabled = true) {
*/
export function useUnreadCounts() {
return useQuery({
queryKey: ['signal-unread-counts'],
queryKey: queryKeys.signal.unreadCounts,
queryFn: async () => {
const { data } = await api.get<UnreadCounts>('/signal/messages/unread');
return data;
@@ -54,8 +55,10 @@ export function useDriverResponseCheck(
// Only include events that have a driver
const eventsWithDrivers = events.filter((e) => e.driver?.id);
const eventIds = eventsWithDrivers.map((e) => e.id).join(',');
return useQuery({
queryKey: ['signal-driver-responses', eventsWithDrivers.map((e) => e.id).join(',')],
queryKey: queryKeys.signal.driverResponses(eventIds),
queryFn: async () => {
if (eventsWithDrivers.length === 0) {
return new Set<string>();
@@ -97,11 +100,11 @@ export function useSendMessage() {
onSuccess: (data, variables) => {
// Add the new message to the cache immediately
queryClient.setQueryData<SignalMessage[]>(
['signal-messages', variables.driverId],
queryKeys.signal.messages(variables.driverId),
(old) => [...(old || []), data]
);
// Also invalidate to ensure consistency
queryClient.invalidateQueries({ queryKey: ['signal-messages', variables.driverId] });
queryClient.invalidateQueries({ queryKey: queryKeys.signal.messages(variables.driverId) });
},
});
}
@@ -120,7 +123,7 @@ export function useMarkMessagesAsRead() {
onSuccess: (_, driverId) => {
// Update the unread counts cache
queryClient.setQueryData<UnreadCounts>(
['signal-unread-counts'],
queryKeys.signal.unreadCounts,
(old) => {
if (!old) return {};
const updated = { ...old };
@@ -130,7 +133,7 @@ export function useMarkMessagesAsRead() {
);
// Mark messages as read in the messages cache
queryClient.setQueryData<SignalMessage[]>(
['signal-messages', driverId],
queryKeys.signal.messages(driverId),
(old) => old?.map((msg) => ({ ...msg, isRead: true })) || []
);
},