/** * dashboard-images-api — Aufrufe des Bilderrahmen-Widgets gegen * /dashboard/images (quick-260921-pi9). Muster favorites-api.ts: Cookie * immer mit (`credentials: 'include'`). * * `uploadDashboardImage` schickt `multipart/form-data` mit genau dem Feld * `image` und OHNE eigenen Content-Type-Header — die Multipart-Grenze setzt * der Browser (Muster bug-report-api.ts). Die deutsche Meldung fuer „zu * gross“ entsteht HIER aus dem Status 413 (multer meldet englisch), die * Meldungen fuer 400 kommen von der API (bereits deutsch). * * `dashboardImageSrc` liefert den Proxy-Pfad fuer ``: der * Next-Rewrite `/api-proxy/:path*` (next.config.ts) reicht Cookies mit, * die Bytes kommen aus Tesseras eigenem Origin (Muster FavoriteIcon). */ const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001'; export interface DashboardImageMeta { id: string; originalName: string; mimeType: string; size: number; createdAt: string; } export async function fetchDashboardImages(): Promise { const res = await fetch(`${API_URL}/dashboard/images`, { credentials: 'include' }); if (!res.ok) throw new Error('Failed to fetch dashboard images'); return res.json(); } export async function uploadDashboardImage(file: File): Promise { const body = new FormData(); body.append('image', file, file.name); const res = await fetch(`${API_URL}/dashboard/images`, { method: 'POST', credentials: 'include', body, }); if (res.ok) return res.json(); if (res.status === 413) { throw new Error('Die Datei ist zu groß – erlaubt sind höchstens 5 MB.'); } if (res.status === 400) { const message = await readMessage(res); if (message) throw new Error(message); } throw new Error('Das Bild konnte nicht hochgeladen werden.'); } export async function deleteDashboardImage(id: string): Promise { const res = await fetch(`${API_URL}/dashboard/images/${encodeURIComponent(id)}`, { method: 'DELETE', credentials: 'include', }); if (!res.ok) throw new Error('Failed to delete dashboard image'); } export function dashboardImageSrc(id: string): string { return `/api-proxy/dashboard/images/${encodeURIComponent(id)}`; } async function readMessage(res: Response): Promise { try { const data: unknown = await res.json(); if (typeof data === 'object' && data !== null && 'message' in data) { const message = (data as { message: unknown }).message; if (typeof message === 'string' && message !== '') return message; } } catch { // kein JSON — allgemeine Meldung } return null; }