export type AcademicPeriod = { id: number; name: string; displayName?: string | null; startDate: string; // YYYY-MM-DD endDate: string; // YYYY-MM-DD periodType: 'schuljahr' | 'semester' | 'trimester'; isActive: boolean; isArchived: boolean; archivedAt?: string | null; archivedBy?: number | null; createdAt?: string; updatedAt?: string; }; export type PeriodUsage = { linked_events: number; has_active_recurrence: boolean; blockers: string[]; }; function normalizeAcademicPeriod(period: any): AcademicPeriod { return { id: Number(period.id), name: period.name, displayName: period.displayName ?? period.display_name ?? null, startDate: period.startDate ?? period.start_date, endDate: period.endDate ?? period.end_date, periodType: period.periodType ?? period.period_type, isActive: Boolean(period.isActive ?? period.is_active), isArchived: Boolean(period.isArchived ?? period.is_archived), archivedAt: period.archivedAt ?? period.archived_at ?? null, archivedBy: period.archivedBy ?? period.archived_by ?? null, createdAt: period.createdAt ?? period.created_at, updatedAt: period.updatedAt ?? period.updated_at, }; } async function api(url: string, init?: RequestInit): Promise { const res = await fetch(url, { credentials: 'include', cache: 'no-store', ...init }); if (!res.ok) { const text = await res.text(); try { const err = JSON.parse(text); throw new Error(err.error || `HTTP ${res.status}`); } catch { throw new Error(`HTTP ${res.status}: ${text}`); } } return res.json(); } export async function getAcademicPeriodForDate(date: Date): Promise { const iso = date.toISOString().slice(0, 10); const { period } = await api<{ period: any | null }>( `/api/academic_periods/for_date?date=${iso}` ); return period ? normalizeAcademicPeriod(period) : null; } export async function listAcademicPeriods(options?: { includeArchived?: boolean; archivedOnly?: boolean; }): Promise { const params = new URLSearchParams(); if (options?.includeArchived) { params.set('includeArchived', '1'); } if (options?.archivedOnly) { params.set('archivedOnly', '1'); } const query = params.toString(); const { periods } = await api<{ periods: any[] }>( `/api/academic_periods${query ? `?${query}` : ''}` ); return Array.isArray(periods) ? periods.map(normalizeAcademicPeriod) : []; } export async function getAcademicPeriod(id: number): Promise { const { period } = await api<{ period: any }>(`/api/academic_periods/${id}`); return normalizeAcademicPeriod(period); } export async function getActiveAcademicPeriod(): Promise { const { period } = await api<{ period: any | null }>(`/api/academic_periods/active`); return period ? normalizeAcademicPeriod(period) : null; } export async function createAcademicPeriod(payload: { name: string; displayName?: string; startDate: string; endDate: string; periodType: 'schuljahr' | 'semester' | 'trimester'; }): Promise { const { period } = await api<{ period: any }>(`/api/academic_periods`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); return normalizeAcademicPeriod(period); } export async function updateAcademicPeriod( id: number, payload: Partial<{ name: string; displayName: string | null; startDate: string; endDate: string; periodType: 'schuljahr' | 'semester' | 'trimester'; }> ): Promise { const { period } = await api<{ period: any }>(`/api/academic_periods/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); return normalizeAcademicPeriod(period); } export async function setActiveAcademicPeriod(id: number): Promise { const { period } = await api<{ period: any }>(`/api/academic_periods/${id}/activate`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, }); return normalizeAcademicPeriod(period); } export async function archiveAcademicPeriod(id: number): Promise { const { period } = await api<{ period: any }>(`/api/academic_periods/${id}/archive`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, }); return normalizeAcademicPeriod(period); } export async function restoreAcademicPeriod(id: number): Promise { const { period } = await api<{ period: any }>(`/api/academic_periods/${id}/restore`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, }); return normalizeAcademicPeriod(period); } export async function getAcademicPeriodUsage(id: number): Promise { const { usage } = await api<{ usage: PeriodUsage }>(`/api/academic_periods/${id}/usage`); return usage; } export async function deleteAcademicPeriod(id: number): Promise { await api(`/api/academic_periods/${id}`, { method: 'DELETE', headers: { 'Content-Type': 'application/json' }, }); }