52 lines
1.6 KiB
TypeScript
52 lines
1.6 KiB
TypeScript
import { useEffect, useState } from 'react';
|
||
|
||
import { BUCKET_REFERENZEN, dateiUrl } from './dateien';
|
||
|
||
/**
|
||
* Bildquelle für ein geschütztes Appwrite-File – **Web**.
|
||
* Gegenstück: `bildquelle.ts`.
|
||
*
|
||
* Warum nicht einfach die URL ins `<img>`: Ein `<img>` schickt bei einer
|
||
* site-fremden Anfrage die Appwrite-Session nicht mit, das Bild bleibt leer.
|
||
* Im Betrieb liegen App und Appwrite unter derselben Domain (`webklar.com`),
|
||
* dort wäre das kein Thema – in der Entwicklung läuft die App aber auf
|
||
* `localhost`, und dann ist jede Anfrage site-fremd.
|
||
*
|
||
* Deshalb wird die Datei einmal per `fetch` mit `credentials: 'include'`
|
||
* geholt und als Object-URL gerendert. Das funktioniert in beiden Fällen und
|
||
* spart die Sonderbehandlung „nur lokal kaputt".
|
||
*/
|
||
export function useBildQuelle(
|
||
fileId?: string,
|
||
bucketId: string = BUCKET_REFERENZEN,
|
||
): { uri: string } | undefined {
|
||
const [uri, setUri] = useState<string>();
|
||
|
||
useEffect(() => {
|
||
if (!fileId) {
|
||
setUri(undefined);
|
||
return;
|
||
}
|
||
let abgebrochen = false;
|
||
let objectUrl: string | undefined;
|
||
|
||
fetch(dateiUrl(fileId, bucketId), { credentials: 'include' })
|
||
.then((r) => (r.ok ? r.blob() : Promise.reject(new Error(`HTTP ${r.status}`))))
|
||
.then((blob) => {
|
||
if (abgebrochen) return;
|
||
objectUrl = URL.createObjectURL(blob);
|
||
setUri(objectUrl);
|
||
})
|
||
.catch(() => {
|
||
if (!abgebrochen) setUri(undefined);
|
||
});
|
||
|
||
return () => {
|
||
abgebrochen = true;
|
||
if (objectUrl) URL.revokeObjectURL(objectUrl);
|
||
};
|
||
}, [fileId, bucketId]);
|
||
|
||
return uri ? { uri } : undefined;
|
||
}
|