rework vehicle handling

This commit is contained in:
Matthias Hochmeister
2026-02-28 14:13:56 +01:00
parent 06f94a6a48
commit b7b883649c
7 changed files with 38 additions and 27 deletions

View File

@@ -560,7 +560,7 @@ class IncidentService {
[targetYear] [targetYear]
); );
const totals = totalsResult.rows[0]; const totals = totalsResult.rows[0] ?? { gesamt: 0, abgeschlossen: 0, aktiv: 0, avg_hilfsfrist_min: null };
// Monthly breakdown — target year // Monthly breakdown — target year
const monthlyResult = await pool.query( const monthlyResult = await pool.query(
@@ -636,21 +636,21 @@ class IncidentService {
const haeufigste_art: EinsatzArt | null = const haeufigste_art: EinsatzArt | null =
byArtResult.rows.length > 0 ? (byArtResult.rows[0].einsatz_art as EinsatzArt) : null; byArtResult.rows.length > 0 ? (byArtResult.rows[0].einsatz_art as EinsatzArt) : null;
const monthly: MonthlyStatRow[] = monthlyResult.rows.map((r) => ({ const monthly: MonthlyStatRow[] = (monthlyResult.rows ?? []).map((r) => ({
monat: r.monat, monat: r.monat,
anzahl: r.anzahl, anzahl: r.anzahl,
avg_hilfsfrist_min: r.avg_hilfsfrist_min !== null ? Number(r.avg_hilfsfrist_min) : null, avg_hilfsfrist_min: r.avg_hilfsfrist_min !== null ? Number(r.avg_hilfsfrist_min) : null,
avg_dauer_min: r.avg_dauer_min !== null ? Number(r.avg_dauer_min) : null, avg_dauer_min: r.avg_dauer_min !== null ? Number(r.avg_dauer_min) : null,
})); }));
const prev_year_monthly: MonthlyStatRow[] = prevMonthlyResult.rows.map((r) => ({ const prev_year_monthly: MonthlyStatRow[] = (prevMonthlyResult.rows ?? []).map((r) => ({
monat: r.monat, monat: r.monat,
anzahl: r.anzahl, anzahl: r.anzahl,
avg_hilfsfrist_min: r.avg_hilfsfrist_min !== null ? Number(r.avg_hilfsfrist_min) : null, avg_hilfsfrist_min: r.avg_hilfsfrist_min !== null ? Number(r.avg_hilfsfrist_min) : null,
avg_dauer_min: r.avg_dauer_min !== null ? Number(r.avg_dauer_min) : null, avg_dauer_min: r.avg_dauer_min !== null ? Number(r.avg_dauer_min) : null,
})); }));
const by_art: EinsatzArtStatRow[] = byArtResult.rows.map((r) => ({ const by_art: EinsatzArtStatRow[] = (byArtResult.rows ?? []).map((r) => ({
einsatz_art: r.einsatz_art as EinsatzArt, einsatz_art: r.einsatz_art as EinsatzArt,
anzahl: r.anzahl, anzahl: r.anzahl,
avg_hilfsfrist_min: r.avg_hilfsfrist_min !== null ? Number(r.avg_hilfsfrist_min) : null, avg_hilfsfrist_min: r.avg_hilfsfrist_min !== null ? Number(r.avg_hilfsfrist_min) : null,

View File

@@ -236,6 +236,8 @@ class MemberService {
// Attach rank history when the profile exists // Attach rank history when the profile exists
if (member.profile) { if (member.profile) {
member.dienstgrad_verlauf = await this.getDienstgradVerlauf(userId); member.dienstgrad_verlauf = await this.getDienstgradVerlauf(userId);
} else {
member.dienstgrad_verlauf = [];
} }
return member; return member;
@@ -583,7 +585,15 @@ class MemberService {
FROM mitglieder_profile FROM mitglieder_profile
`); `);
return result.rows[0] as MemberStats; return (result.rows[0] as MemberStats) ?? {
total: 0,
aktiv: 0,
passiv: 0,
ehrenmitglied: 0,
jugendfeuerwehr: 0,
'anwärter': 0,
ausgetreten: 0,
};
} catch (error) { } catch (error) {
logger.error('Error fetching member stats', { error }); logger.error('Error fetching member stats', { error });
throw new Error('Failed to fetch member stats'); throw new Error('Failed to fetch member stats');

View File

@@ -373,16 +373,16 @@ class VehicleService {
WHERE deleted_at IS NULL WHERE deleted_at IS NULL
`); `);
const totals = totalsResult.rows[0]; const totals = totalsResult.rows[0] ?? { total: '0', einsatzbereit: '0', ausser_dienst: '0', in_lehrgang: '0' };
const alerts = alertResult.rows[0]; const alerts = alertResult.rows[0] ?? { inspections_due: '0', inspections_overdue: '0' };
return { return {
total: parseInt(totals.total, 10), total: parseInt(totals.total ?? '0', 10),
einsatzbereit: parseInt(totals.einsatzbereit, 10), einsatzbereit: parseInt(totals.einsatzbereit ?? '0', 10),
ausserDienst: parseInt(totals.ausser_dienst, 10), ausserDienst: parseInt(totals.ausser_dienst ?? '0', 10),
inLehrgang: parseInt(totals.in_lehrgang, 10), inLehrgang: parseInt(totals.in_lehrgang ?? '0', 10),
inspectionsDue: parseInt(alerts.inspections_due, 10), inspectionsDue: parseInt(alerts.inspections_due ?? '0', 10),
inspectionsOverdue: parseInt(alerts.inspections_overdue, 10), inspectionsOverdue: parseInt(alerts.inspections_overdue ?? '0', 10),
}; };
} catch (error) { } catch (error) {
logger.error('VehicleService.getVehicleStats failed', { error }); logger.error('VehicleService.getVehicleStats failed', { error });

View File

@@ -14,6 +14,7 @@ import {
Fab, Fab,
FormControl, FormControl,
Grid, Grid,
IconButton,
InputLabel, InputLabel,
MenuItem, MenuItem,
Paper, Paper,

View File

@@ -216,7 +216,7 @@ export const incidentsApi = {
const response = await api.get<{ success: boolean; data: IncidentListResponse }>( const response = await api.get<{ success: boolean; data: IncidentListResponse }>(
`/api/incidents?${params.toString()}` `/api/incidents?${params.toString()}`
); );
if (!response.data?.data) { if (response.data?.data === undefined || response.data?.data === null) {
throw new Error('Invalid API response'); throw new Error('Invalid API response');
} }
return response.data.data; return response.data.data;
@@ -230,7 +230,7 @@ export const incidentsApi = {
const response = await api.get<{ success: boolean; data: EinsatzStats }>( const response = await api.get<{ success: boolean; data: EinsatzStats }>(
`/api/incidents/stats${params}` `/api/incidents/stats${params}`
); );
if (!response.data?.data) { if (response.data?.data === undefined || response.data?.data === null) {
throw new Error('Invalid API response'); throw new Error('Invalid API response');
} }
return response.data.data; return response.data.data;
@@ -243,7 +243,7 @@ export const incidentsApi = {
const response = await api.get<{ success: boolean; data: EinsatzDetail }>( const response = await api.get<{ success: boolean; data: EinsatzDetail }>(
`/api/incidents/${id}` `/api/incidents/${id}`
); );
if (!response.data?.data) { if (response.data?.data === undefined || response.data?.data === null) {
throw new Error('Invalid API response'); throw new Error('Invalid API response');
} }
return response.data.data; return response.data.data;
@@ -257,7 +257,7 @@ export const incidentsApi = {
'/api/incidents', '/api/incidents',
payload payload
); );
if (!response.data?.data) { if (response.data?.data === undefined || response.data?.data === null) {
throw new Error('Invalid API response'); throw new Error('Invalid API response');
} }
return response.data.data; return response.data.data;
@@ -271,7 +271,7 @@ export const incidentsApi = {
`/api/incidents/${id}`, `/api/incidents/${id}`,
payload payload
); );
if (!response.data?.data) { if (response.data?.data === undefined || response.data?.data === null) {
throw new Error('Invalid API response'); throw new Error('Invalid API response');
} }
return response.data.data; return response.data.data;

View File

@@ -55,7 +55,7 @@ export const membersService = {
const response = await api.get<ApiListResponse<MemberListItem>>( const response = await api.get<ApiListResponse<MemberListItem>>(
`/api/members?${params.toString()}` `/api/members?${params.toString()}`
); );
if (!response.data?.data) { if (response.data?.data === undefined || response.data?.data === null) {
throw new Error('Invalid API response'); throw new Error('Invalid API response');
} }
return { return {
@@ -72,7 +72,7 @@ export const membersService = {
const response = await api.get<ApiItemResponse<MemberWithProfile>>( const response = await api.get<ApiItemResponse<MemberWithProfile>>(
`/api/members/${userId}` `/api/members/${userId}`
); );
if (!response.data?.data) { if (response.data?.data === undefined || response.data?.data === null) {
throw new Error('Invalid API response'); throw new Error('Invalid API response');
} }
return response.data.data; return response.data.data;
@@ -90,7 +90,7 @@ export const membersService = {
`/api/members/${userId}/profile`, `/api/members/${userId}/profile`,
data data
); );
if (!response.data?.data) { if (response.data?.data === undefined || response.data?.data === null) {
throw new Error('Invalid API response'); throw new Error('Invalid API response');
} }
return response.data.data; return response.data.data;
@@ -109,7 +109,7 @@ export const membersService = {
`/api/members/${userId}`, `/api/members/${userId}`,
data data
); );
if (!response.data?.data) { if (response.data?.data === undefined || response.data?.data === null) {
throw new Error('Invalid API response'); throw new Error('Invalid API response');
} }
return response.data.data; return response.data.data;
@@ -120,7 +120,7 @@ export const membersService = {
*/ */
async getMemberStats(): Promise<MemberStats> { async getMemberStats(): Promise<MemberStats> {
const response = await api.get<ApiItemResponse<MemberStats>>('/api/members/stats'); const response = await api.get<ApiItemResponse<MemberStats>>('/api/members/stats');
if (!response.data?.data) { if (response.data?.data === undefined || response.data?.data === null) {
throw new Error('Invalid API response'); throw new Error('Invalid API response');
} }
return response.data.data; return response.data.data;

View File

@@ -15,7 +15,7 @@ async function unwrap<T>(
promise: ReturnType<typeof api.get<{ success: boolean; data: T }>> promise: ReturnType<typeof api.get<{ success: boolean; data: T }>>
): Promise<T> { ): Promise<T> {
const response = await promise; const response = await promise;
if (!response.data?.data) { if (response.data?.data === undefined || response.data?.data === null) {
throw new Error('Invalid API response'); throw new Error('Invalid API response');
} }
return response.data.data; return response.data.data;
@@ -47,7 +47,7 @@ export const vehiclesApi = {
'/api/vehicles', '/api/vehicles',
payload payload
); );
if (!response.data?.data) { if (response.data?.data === undefined || response.data?.data === null) {
throw new Error('Invalid API response'); throw new Error('Invalid API response');
} }
return response.data.data; return response.data.data;
@@ -58,7 +58,7 @@ export const vehiclesApi = {
`/api/vehicles/${id}`, `/api/vehicles/${id}`,
payload payload
); );
if (!response.data?.data) { if (response.data?.data === undefined || response.data?.data === null) {
throw new Error('Invalid API response'); throw new Error('Invalid API response');
} }
return response.data.data; return response.data.data;
@@ -83,7 +83,7 @@ export const vehiclesApi = {
`/api/vehicles/${id}/wartung`, `/api/vehicles/${id}/wartung`,
payload payload
); );
if (!response.data?.data) { if (response.data?.data === undefined || response.data?.data === null) {
throw new Error('Invalid API response'); throw new Error('Invalid API response');
} }
return response.data.data; return response.data.data;