bug fix for atemschutz

This commit is contained in:
Matthias Hochmeister
2026-03-01 19:19:12 +01:00
parent 2630224edd
commit 6495ca94d1
17 changed files with 5116 additions and 0 deletions

View File

@@ -0,0 +1,117 @@
import { api } from './api';
import type {
FahrzeugBuchungListItem,
FahrzeugBuchung,
Fahrzeug,
CreateBuchungInput,
} from '../types/booking.types';
// ---------------------------------------------------------------------------
// Response shapes from the backend
// ---------------------------------------------------------------------------
interface ApiResponse<T> {
success: boolean;
data: T;
}
// ---------------------------------------------------------------------------
// Booking API service
// ---------------------------------------------------------------------------
export const bookingApi = {
// -------------------------------------------------------------------------
// Calendar / listing
// -------------------------------------------------------------------------
getCalendarRange(from: Date, to: Date, fahrzeugId?: string): Promise<FahrzeugBuchungListItem[]> {
return api
.get<ApiResponse<FahrzeugBuchungListItem[]>>('/api/bookings/calendar', {
params: {
from: from.toISOString(),
to: to.toISOString(),
...(fahrzeugId ? { fahrzeugId } : {}),
},
})
.then((r) => r.data.data);
},
getUpcoming(limit = 20): Promise<FahrzeugBuchungListItem[]> {
return api
.get<ApiResponse<FahrzeugBuchungListItem[]>>('/api/bookings/upcoming', {
params: { limit },
})
.then((r) => r.data.data);
},
// -------------------------------------------------------------------------
// Availability check
// -------------------------------------------------------------------------
checkAvailability(
fahrzeugId: string,
from: Date,
to: Date
): Promise<{ available: boolean }> {
return api
.get<ApiResponse<{ available: boolean }>>('/api/bookings/availability', {
params: {
fahrzeugId,
from: from.toISOString(),
to: to.toISOString(),
},
})
.then((r) => r.data.data);
},
// -------------------------------------------------------------------------
// Single booking
// -------------------------------------------------------------------------
getById(id: string): Promise<FahrzeugBuchung> {
return api
.get<ApiResponse<FahrzeugBuchung>>(`/api/bookings/${id}`)
.then((r) => r.data.data);
},
// -------------------------------------------------------------------------
// CRUD
// -------------------------------------------------------------------------
create(data: CreateBuchungInput): Promise<FahrzeugBuchung> {
return api
.post<ApiResponse<FahrzeugBuchung>>('/api/bookings', data)
.then((r) => r.data.data);
},
update(id: string, data: Partial<CreateBuchungInput>): Promise<FahrzeugBuchung> {
return api
.patch<ApiResponse<FahrzeugBuchung>>(`/api/bookings/${id}`, data)
.then((r) => r.data.data);
},
cancel(id: string, abgesagt_grund: string): Promise<void> {
return api
.delete(`/api/bookings/${id}`, { data: { abgesagt_grund } })
.then(() => undefined);
},
// -------------------------------------------------------------------------
// iCal
// -------------------------------------------------------------------------
getCalendarToken(): Promise<{ token: string; subscribeUrl: string }> {
return api
.get<ApiResponse<{ token: string; subscribeUrl: string }>>(
'/api/bookings/calendar-token'
)
.then((r) => r.data.data);
},
};
// ---------------------------------------------------------------------------
// Vehicle helper (shared with booking page)
// ---------------------------------------------------------------------------
export function fetchVehicles(): Promise<Fahrzeug[]> {
return api
.get<ApiResponse<Fahrzeug[]>>('/api/vehicles')
.then((r) => r.data.data.filter((v: Fahrzeug) => !v.archived_at));
}

View File

@@ -0,0 +1,143 @@
import { api } from './api';
import type {
VeranstaltungKategorie,
VeranstaltungListItem,
Veranstaltung,
GroupInfo,
CreateVeranstaltungInput,
} from '../types/events.types';
// ---------------------------------------------------------------------------
// Response shapes from the backend
// ---------------------------------------------------------------------------
interface ApiResponse<T> {
success: boolean;
data: T;
message?: string;
}
// ---------------------------------------------------------------------------
// Events API service
// ---------------------------------------------------------------------------
export const eventsApi = {
// -------------------------------------------------------------------------
// Kategorien (Categories)
// -------------------------------------------------------------------------
/** List all event categories */
getKategorien(): Promise<VeranstaltungKategorie[]> {
return api
.get<ApiResponse<VeranstaltungKategorie[]>>('/api/events/kategorien')
.then((r) => r.data.data);
},
/** Create a new event category */
createKategorie(data: {
name: string;
beschreibung?: string;
farbe?: string;
icon?: string;
}): Promise<VeranstaltungKategorie> {
return api
.post<ApiResponse<VeranstaltungKategorie>>('/api/events/kategorien', data)
.then((r) => r.data.data);
},
/** Update an existing event category */
updateKategorie(
id: string,
data: Partial<{ name: string; beschreibung?: string; farbe?: string; icon?: string }>
): Promise<VeranstaltungKategorie> {
return api
.patch<ApiResponse<VeranstaltungKategorie>>(`/api/events/kategorien/${id}`, data)
.then((r) => r.data.data);
},
/** Delete an event category */
deleteKategorie(id: string): Promise<void> {
return api
.delete(`/api/events/kategorien/${id}`)
.then(() => undefined);
},
// -------------------------------------------------------------------------
// Groups
// -------------------------------------------------------------------------
/** List all available target groups */
getGroups(): Promise<GroupInfo[]> {
return api
.get<ApiResponse<GroupInfo[]>>('/api/events/groups')
.then((r) => r.data.data);
},
// -------------------------------------------------------------------------
// Event listing
// -------------------------------------------------------------------------
/** Events in a date range for the month calendar view */
getCalendarRange(from: Date, to: Date): Promise<VeranstaltungListItem[]> {
return api
.get<ApiResponse<VeranstaltungListItem[]>>('/api/events/calendar', {
params: {
from: from.toISOString(),
to: to.toISOString(),
},
})
.then((r) => r.data.data);
},
/** Upcoming events (dashboard widget, list view) */
getUpcoming(limit = 10): Promise<VeranstaltungListItem[]> {
return api
.get<ApiResponse<VeranstaltungListItem[]>>('/api/events/upcoming', {
params: { limit },
})
.then((r) => r.data.data);
},
/** Full event detail */
getById(id: string): Promise<Veranstaltung> {
return api
.get<ApiResponse<Veranstaltung>>(`/api/events/${id}`)
.then((r) => r.data.data);
},
// -------------------------------------------------------------------------
// CRUD
// -------------------------------------------------------------------------
/** Create a new event */
createEvent(data: CreateVeranstaltungInput): Promise<Veranstaltung> {
return api
.post<ApiResponse<Veranstaltung>>('/api/events', data)
.then((r) => r.data.data);
},
/** Update an existing event */
updateEvent(id: string, data: Partial<CreateVeranstaltungInput>): Promise<Veranstaltung> {
return api
.patch<ApiResponse<Veranstaltung>>(`/api/events/${id}`, data)
.then((r) => r.data.data);
},
/** Cancel (soft-delete) an event with a reason */
cancelEvent(id: string, abgesagt_grund: string): Promise<void> {
return api
.delete(`/api/events/${id}`, { data: { abgesagt_grund } })
.then(() => undefined);
},
// -------------------------------------------------------------------------
// iCal
// -------------------------------------------------------------------------
/** Get the user's personal calendar subscribe URL */
getCalendarToken(): Promise<{ token: string; subscribeUrl: string }> {
return api
.get<ApiResponse<{ token: string; subscribeUrl: string }>>(
'/api/events/calendar-token'
)
.then((r) => r.data.data);
},
};