import { api } from './api'; import { MemberListItem, MemberWithProfile, MemberFilters, MemberStats, CreateMemberProfileData, UpdateMemberProfileData, Befoerderung, Untersuchung, Fahrgenehmigung, Ausbildung, } from '../types/member.types'; // ---------------------------------------------------------------- // Response envelope shapes // ---------------------------------------------------------------- interface ApiListResponse { success: boolean; data: T[]; meta: { total: number; page: number }; } interface ApiItemResponse { success: boolean; data: T; } // ---------------------------------------------------------------- // Service // ---------------------------------------------------------------- /** * Builds a URLSearchParams object from the filter object so query * strings like ?status[]=aktiv&status[]=jugend are sent correctly. */ function buildParams(filters?: MemberFilters): URLSearchParams { const params = new URLSearchParams(); if (!filters) return params; if (filters.search) params.append('search', filters.search); if (filters.page) params.append('page', String(filters.page)); if (filters.pageSize !== undefined) params.append('pageSize', String(filters.pageSize)); filters.status?.forEach((s) => params.append('status[]', s)); filters.dienstgrad?.forEach((d) => params.append('dienstgrad[]', d)); if (filters.sortBy) params.append('sortBy', filters.sortBy); if (filters.sortDir) params.append('sortDir', filters.sortDir); return params; } export const membersService = { /** * Fetches a paginated, optionally filtered list of members. */ async getMembers( filters?: MemberFilters ): Promise<{ items: MemberListItem[]; total: number; page: number }> { const params = buildParams(filters); const response = await api.get>( `/api/members?${params.toString()}` ); if (response.data?.data === undefined || response.data?.data === null) { throw new Error('Invalid API response'); } return { items: response.data.data, total: response.data.meta?.total ?? 0, page: response.data.meta?.page ?? 1, }; }, /** * Fetches a single member with their full profile and rank history. */ async getMember(userId: string): Promise { const response = await api.get>( `/api/members/${userId}` ); if (response.data?.data === undefined || response.data?.data === null) { throw new Error('Invalid API response'); } return response.data.data; }, /** * Creates a new member profile for an existing auth user. * Restricted to Kommandant/Admin (enforced server-side). */ async createMemberProfile( userId: string, data: CreateMemberProfileData ): Promise { const response = await api.post>( `/api/members/${userId}/profile`, data ); if (response.data?.data === undefined || response.data?.data === null) { throw new Error('Invalid API response'); } return response.data.data; }, /** * Partially updates a member profile. * Kommandant/Admin: full update. * Own profile: limited fields only (enforced server-side). */ async updateMember( userId: string, data: UpdateMemberProfileData ): Promise { const response = await api.patch>( `/api/members/${userId}`, data ); if (response.data?.data === undefined || response.data?.data === null) { throw new Error('Invalid API response'); } return response.data.data; }, /** * Fetches aggregate counts for the dashboard KPI widget. */ async getMemberStats(): Promise { const response = await api.get>('/api/members/stats'); if (response.data?.data === undefined || response.data?.data === null) { throw new Error('Invalid API response'); } return response.data.data; }, async getBefoerderungen(userId: string): Promise { const response = await api.get>(`/api/members/${userId}/befoerderungen`); return response.data?.data ?? []; }, async getUntersuchungen(userId: string): Promise { const response = await api.get>(`/api/members/${userId}/untersuchungen`); return response.data?.data ?? []; }, async getFahrgenehmigungen(userId: string): Promise { const response = await api.get>(`/api/members/${userId}/fahrgenehmigungen`); return response.data?.data ?? []; }, async getAusbildungen(userId: string): Promise { const response = await api.get>(`/api/members/${userId}/ausbildungen`); return response.data?.data ?? []; }, };