import { redirect } from '@sveltejs/kit'; import { createApiClient } from '$lib/shared/api.server'; import type { components } from '$lib/generated/api'; type StatsDTO = components['schemas']['StatsDTO']; type TranscriptionQueueItemDTO = components['schemas']['TranscriptionQueueItemDTO']; type TranscriptionWeeklyStatsDTO = components['schemas']['TranscriptionWeeklyStatsDTO']; type DashboardResumeDTO = components['schemas']['DashboardResumeDTO']; type DashboardPulseDTO = components['schemas']['DashboardPulseDTO']; type ActivityFeedItemDTO = components['schemas']['ActivityFeedItemDTO']; type IncompleteDocumentDTO = components['schemas']['IncompleteDocumentDTO']; type PersonSummaryDTO = components['schemas']['PersonSummaryDTO']; type Document = components['schemas']['Document']; type Geschichte = components['schemas']['Geschichte']; function settled(res: PromiseSettledResult | undefined): T | null { if (res?.status !== 'fulfilled') return null; const v = res.value as { response: Response; data: unknown }; return v.response.ok ? ((v.data as T) ?? null) : null; } export async function load({ fetch, parent }) { const { canWrite, canAnnotate, canBlogWrite } = await parent(); // READ_ALL without WRITE_ALL or ANNOTATE_ALL — see ADR-007. // BLOG_WRITE-only users land here too and see the drafts module on top. const isReader = !canWrite && !canAnnotate; const api = createApiClient(fetch); try { const personsResult = await api.GET('/api/persons'); if (personsResult.response.status === 401) { throw redirect(302, '/login'); } if (isReader) { const readerFetches: Promise[] = [ api.GET('/api/stats'), api.GET('/api/persons', { params: { query: { size: 4, sort: 'documentCount' } } }), api.GET('/api/documents/search', { params: { query: { sort: 'UPDATED_AT', dir: 'DESC', size: 5 } } }), api.GET('/api/geschichten', { params: { query: { status: 'PUBLISHED', limit: 3 } } }) ]; if (canBlogWrite) { readerFetches.push( api.GET('/api/geschichten', { params: { query: { status: 'DRAFT', limit: 10 } } }) ); } const [statsRes, topPersonsRes, recentDocsRes, recentStoriesRes, draftsRes] = await Promise.allSettled(readerFetches); const readerStats = settled(statsRes); const topPersons = settled(topPersonsRes) ?? []; const searchData = settled<{ items: { document: Document }[] }>(recentDocsRes); const recentDocs = searchData?.items.map((i) => i.document) ?? []; const recentStories = settled(recentStoriesRes) ?? []; const drafts = settled(draftsRes) ?? []; return { isReader: true as const, canBlogWrite, readerStats, topPersons, recentDocs, recentStories, drafts, error: null as string | null }; } const [ statsResult, resumeResult, pulseResult, activityResult, segmentationResult, transcriptionResult, readyResult, weeklyStatsResult, incompleteResult, incompleteCountResult ] = await Promise.allSettled([ api.GET('/api/stats'), api.GET('/api/dashboard/resume'), api.GET('/api/dashboard/pulse'), api.GET('/api/dashboard/activity', { params: { query: { limit: 7 } } }), api.GET('/api/transcription/segmentation-queue'), api.GET('/api/transcription/transcription-queue'), api.GET('/api/transcription/ready-to-read'), api.GET('/api/transcription/weekly-stats'), api.GET('/api/documents/incomplete', { params: { query: { size: 5 } } }), api.GET('/api/documents/incomplete-count') ]); let stats: StatsDTO | null = null; let resumeDoc: DashboardResumeDTO | null = null; let pulse: DashboardPulseDTO | null = null; let activityFeed: ActivityFeedItemDTO[] = []; let segmentationDocs: TranscriptionQueueItemDTO[] = []; let transcriptionDocs: TranscriptionQueueItemDTO[] = []; let readyDocs: TranscriptionQueueItemDTO[] = []; let weeklyStats: TranscriptionWeeklyStatsDTO | null = null; let incompleteDocs: IncompleteDocumentDTO[] = []; let incompleteTotal = 0; if (statsResult.status === 'fulfilled' && statsResult.value.response.ok) { stats = statsResult.value.data ?? null; } if (resumeResult.status === 'fulfilled' && resumeResult.value.response.ok) { resumeDoc = (resumeResult.value.data as DashboardResumeDTO) ?? null; } if (pulseResult.status === 'fulfilled' && pulseResult.value.response.ok) { pulse = (pulseResult.value.data as DashboardPulseDTO) ?? null; } if (activityResult.status === 'fulfilled' && activityResult.value.response.ok) { activityFeed = (activityResult.value.data as ActivityFeedItemDTO[]) ?? []; } if (segmentationResult.status === 'fulfilled' && segmentationResult.value.response.ok) { segmentationDocs = (segmentationResult.value.data ?? []) as TranscriptionQueueItemDTO[]; } if (transcriptionResult.status === 'fulfilled' && transcriptionResult.value.response.ok) { transcriptionDocs = (transcriptionResult.value.data ?? []) as TranscriptionQueueItemDTO[]; } if (readyResult.status === 'fulfilled' && readyResult.value.response.ok) { readyDocs = (readyResult.value.data ?? []) as TranscriptionQueueItemDTO[]; } if (weeklyStatsResult.status === 'fulfilled' && weeklyStatsResult.value.response.ok) { weeklyStats = weeklyStatsResult.value.data ?? null; } if (incompleteResult.status === 'fulfilled' && incompleteResult.value.response.ok) { incompleteDocs = (incompleteResult.value.data ?? []) as IncompleteDocumentDTO[]; } if (incompleteCountResult.status === 'fulfilled' && incompleteCountResult.value.response.ok) { incompleteTotal = (incompleteCountResult.value.data?.count as number | undefined) ?? 0; } return { isReader: false as const, stats, resumeDoc, pulse, activityFeed, segmentationDocs, transcriptionDocs, readyDocs, weeklyStats, incompleteDocs, incompleteTotal, error: null as string | null }; } catch (e) { if ((e as { status?: number }).status) throw e; console.error('Error loading data:', e); return { isReader, stats: null, resumeDoc: null, pulse: null, activityFeed: [], segmentationDocs: [], transcriptionDocs: [], readyDocs: [], weeklyStats: null, incompleteDocs: [] as IncompleteDocumentDTO[], incompleteTotal: 0, readerStats: null, topPersons: [] as PersonSummaryDTO[], recentDocs: [] as Document[], recentStories: [] as Geschichte[], drafts: [] as Geschichte[], error: 'Daten konnten nicht geladen werden.' as string | null }; } }