import { api } from './api'; // --------------------------------------------------------------------------- // SHARED TYPES (mirrors backend models, kept lean for frontend consumption) // --------------------------------------------------------------------------- export const EINSATZ_ARTEN = [ 'Brand', 'THL', 'ABC', 'BMA', 'Hilfeleistung', 'Fehlalarm', 'Brandsicherheitswache', ] as const; export type EinsatzArt = (typeof EINSATZ_ARTEN)[number]; export const EINSATZ_ART_LABELS: Record = { Brand: 'Brand', THL: 'Technische Hilfeleistung', ABC: 'ABC / Gefahrgut', BMA: 'Brandmeldeanlage', Hilfeleistung: 'Hilfeleistung', Fehlalarm: 'Fehlalarm', Brandsicherheitswache: 'Brandsicherheitswache', }; export const EINSATZ_STATUS = ['aktiv', 'abgeschlossen', 'archiviert'] as const; export type EinsatzStatus = (typeof EINSATZ_STATUS)[number]; export const EINSATZ_STATUS_LABELS: Record = { aktiv: 'Aktiv', abgeschlossen: 'Abgeschlossen', archiviert: 'Archiviert', }; export const EINSATZ_FUNKTIONEN = [ 'Einsatzleiter', 'Gruppenführer', 'Maschinist', 'Atemschutz', 'Sicherheitstrupp', 'Melder', 'Wassertrupp', 'Angriffstrupp', 'Mannschaft', 'Sonstiges', ] as const; export type EinsatzFunktion = (typeof EINSATZ_FUNKTIONEN)[number]; // --------------------------------------------------------------------------- // API RESPONSE SHAPES // --------------------------------------------------------------------------- export interface EinsatzListItem { id: string; einsatz_nr: string; alarm_time: string; // ISO 8601 string from JSON einsatz_art: EinsatzArt; einsatz_stichwort: string | null; ort: string | null; strasse: string | null; status: EinsatzStatus; einsatzleiter_name: string | null; hilfsfrist_min: number | null; dauer_min: number | null; personal_count: number; } export interface EinsatzPersonal { einsatz_id: string; user_id: string; funktion: EinsatzFunktion; alarm_time: string | null; ankunft_time: string | null; assigned_at: string; name: string | null; email: string; given_name: string | null; family_name: string | null; } export interface EinsatzFahrzeug { einsatz_id: string; fahrzeug_id: string; ausrueck_time: string | null; einrueck_time: string | null; assigned_at: string; kennzeichen: string; bezeichnung: string; fahrzeug_typ: string | null; } export interface EinsatzDetail { id: string; einsatz_nr: string; alarm_time: string; ausrueck_time: string | null; ankunft_time: string | null; einrueck_time: string | null; einsatz_art: EinsatzArt; einsatz_stichwort: string | null; strasse: string | null; hausnummer: string | null; ort: string | null; bericht_kurz: string | null; bericht_text: string | null; // undefined/null for roles below Kommandant einsatzleiter_id: string | null; einsatzleiter_name: string | null; alarmierung_art: string; status: EinsatzStatus; created_by: string | null; created_at: string; updated_at: string; hilfsfrist_min: number | null; dauer_min: number | null; fahrzeuge: EinsatzFahrzeug[]; personal: EinsatzPersonal[]; } export interface MonthlyStatRow { monat: number; anzahl: number; avg_hilfsfrist_min: number | null; avg_dauer_min: number | null; } export interface EinsatzArtStatRow { einsatz_art: EinsatzArt; anzahl: number; avg_hilfsfrist_min: number | null; } export interface EinsatzStats { jahr: number; gesamt: number; abgeschlossen: number; aktiv: number; avg_hilfsfrist_min: number | null; haeufigste_art: EinsatzArt | null; monthly: MonthlyStatRow[]; by_art: EinsatzArtStatRow[]; prev_year_monthly: MonthlyStatRow[]; } export interface IncidentListResponse { items: EinsatzListItem[]; total: number; limit: number; offset: number; } // --------------------------------------------------------------------------- // REQUEST SHAPES // --------------------------------------------------------------------------- export interface IncidentFilters { dateFrom?: string; dateTo?: string; einsatzArt?: EinsatzArt; status?: EinsatzStatus; limit?: number; offset?: number; } export interface CreateEinsatzPayload { alarm_time: string; ausrueck_time?: string | null; ankunft_time?: string | null; einrueck_time?: string | null; einsatz_art: EinsatzArt; einsatz_stichwort?: string | null; strasse?: string | null; hausnummer?: string | null; ort?: string | null; bericht_kurz?: string | null; bericht_text?: string | null; einsatzleiter_id?: string | null; alarmierung_art?: string; status?: EinsatzStatus; } export type UpdateEinsatzPayload = Partial; export interface AssignPersonnelPayload { user_id: string; funktion?: EinsatzFunktion; alarm_time?: string | null; ankunft_time?: string | null; } export interface AssignVehiclePayload { fahrzeug_id: string; ausrueck_time?: string | null; einrueck_time?: string | null; } // --------------------------------------------------------------------------- // API CALLS // --------------------------------------------------------------------------- export const incidentsApi = { /** * Fetch paginated incident list with optional filters. */ async getAll(filters: IncidentFilters = {}): Promise { const params = new URLSearchParams(); if (filters.dateFrom) params.set('dateFrom', filters.dateFrom); if (filters.dateTo) params.set('dateTo', filters.dateTo); if (filters.einsatzArt) params.set('einsatzArt', filters.einsatzArt); if (filters.status) params.set('status', filters.status); if (filters.limit !== undefined) params.set('limit', String(filters.limit)); if (filters.offset !== undefined) params.set('offset', String(filters.offset)); const response = await api.get<{ success: boolean; data: IncidentListResponse }>( `/api/incidents?${params.toString()}` ); if (response.data?.data === undefined || response.data?.data === null) { throw new Error('Invalid API response'); } return response.data.data; }, /** * Fetch aggregated statistics for a given year. */ async getStats(year?: number): Promise { const params = year ? `?year=${year}` : ''; const response = await api.get<{ success: boolean; data: EinsatzStats }>( `/api/incidents/stats${params}` ); if (response.data?.data === undefined || response.data?.data === null) { throw new Error('Invalid API response'); } return response.data.data; }, /** * Fetch a single incident with full detail. */ async getById(id: string): Promise { const response = await api.get<{ success: boolean; data: EinsatzDetail }>( `/api/incidents/${id}` ); if (response.data?.data === undefined || response.data?.data === null) { throw new Error('Invalid API response'); } return response.data.data; }, /** * Create a new incident. Returns the created Einsatz row. */ async create(payload: CreateEinsatzPayload): Promise { const response = await api.post<{ success: boolean; data: EinsatzDetail }>( '/api/incidents', payload ); if (response.data?.data === undefined || response.data?.data === null) { throw new Error('Invalid API response'); } return response.data.data; }, /** * Partially update an incident. */ async update(id: string, payload: UpdateEinsatzPayload): Promise { const response = await api.patch<{ success: boolean; data: EinsatzDetail }>( `/api/incidents/${id}`, payload ); if (response.data?.data === undefined || response.data?.data === null) { throw new Error('Invalid API response'); } return response.data.data; }, /** * Soft-delete (archive) an incident. */ async delete(id: string): Promise { await api.delete(`/api/incidents/${id}`); }, /** * Assign a member to an incident. */ async assignPersonnel(einsatzId: string, payload: AssignPersonnelPayload): Promise { await api.post(`/api/incidents/${einsatzId}/personnel`, payload); }, /** * Remove a member from an incident. */ async removePersonnel(einsatzId: string, userId: string): Promise { await api.delete(`/api/incidents/${einsatzId}/personnel/${userId}`); }, /** * Assign a vehicle to an incident. */ async assignVehicle(einsatzId: string, payload: AssignVehiclePayload): Promise { await api.post(`/api/incidents/${einsatzId}/vehicles`, payload); }, /** * Remove a vehicle from an incident. */ async removeVehicle(einsatzId: string, fahrzeugId: string): Promise { await api.delete(`/api/incidents/${einsatzId}/vehicles/${fahrzeugId}`); }, };