c080580459
- picture-frame-config.ts: Eintragstyp als Vereinigung (upload | url) in EINER geordneten Liste, resolvePictureFrameConfig laesst alles ausser https weg (T-PI9-07), Intervall 0 oder 5..3600 s, pickNextIndex (Zufall nie dasselbe) - dashboard-images-api.ts: Upload als FormData-Feld image ohne eigenen Content-Type, 413 -> deutsche Meldung, Proxy-Pfad fuer <img src> - PictureFrameWidget: Leerzustand, <img referrerPolicy=no-referrer> (Browser laedt Fremdbilder, Server nie), object-contain/cover, Unterschrift-Streifen, Wechsel per Timer mit Raeumung, kaputte Bilder verlassen den Umlauf, Grossansicht nur ausserhalb des Bearbeitungsmodus mit Fokus-Rueckgabe und Pause des Wechsels; im Bearbeitungsmodus kein Knopf (Karte bleibt Griff) - PictureFrameConfigForm im WidgetSettingsPanel: Ausschnitt, Intervall, Reihenfolge, Liste mit Vorschau/Unterschrift/Pfeilen/Entfernen (Upload wird auch serverseitig geloescht), Datei hochladen, https-Adresse hinzufuegen - Registry (4x4 min, 8x8 Vorgabe), Katalog, Seite, Uebersetzungen de/en (widgets.pictureFrame, 28 Schluessel), bestehende Tests auf acht Typen Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
77 lines
2.6 KiB
TypeScript
77 lines
2.6 KiB
TypeScript
/**
|
||
* 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 `<img src>`: 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<DashboardImageMeta[]> {
|
||
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<DashboardImageMeta> {
|
||
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<void> {
|
||
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<string | null> {
|
||
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;
|
||
}
|