diff --git a/web/src/components/ProduktBild.jsx b/web/src/components/ProduktBild.jsx
index 7104832..3a9cdcf 100644
--- a/web/src/components/ProduktBild.jsx
+++ b/web/src/components/ProduktBild.jsx
@@ -1,4 +1,4 @@
-import { useEffect, useState } from "react";
+import { useEffect, useRef, useState } from "react";
import { authorizedObjectUrl } from "../api";
import Icon from "./Icon";
@@ -7,9 +7,16 @@ import Icon from "./Icon";
*
* Die Objekt-URL wird beim Verlassen wieder freigegeben, sonst hält der Browser
* jedes angesehene Bild bis zum Neuladen der Seite im Speicher.
+ *
+ * ``onLoaded`` meldet, ob ein Bild vorliegt – so kann die Artikelseite z.B. den
+ * „Entfernen"-Knopf ausblenden, wenn es nichts zu entfernen gibt.
*/
-function useBildUrl(productId, version = 0) {
+function useBildUrl(productId, version = 0, onLoaded) {
const [url, setUrl] = useState(null);
+ // Über einen Ref, damit ein bei jedem Render neu erzeugtes onLoaded den Effekt
+ // nicht erneut auslöst.
+ const onLoadedRef = useRef(onLoaded);
+ onLoadedRef.current = onLoaded;
useEffect(() => {
if (!productId) return undefined;
@@ -20,15 +27,21 @@ function useBildUrl(productId, version = 0) {
// Speichern nicht seine zwischengespeicherte Fassung ausliefert.
authorizedObjectUrl(`/products/${productId}/image${version ? `?v=${version}` : ""}`)
.then((neu) => {
- if (!neu) return;
if (abgebrochen) {
- URL.revokeObjectURL(neu);
+ if (neu) URL.revokeObjectURL(neu);
+ return;
+ }
+ onLoadedRef.current?.(Boolean(neu));
+ if (!neu) {
+ setUrl(null);
return;
}
erzeugt = neu;
setUrl(neu);
})
- .catch(() => {});
+ .catch(() => {
+ if (!abgebrochen) onLoadedRef.current?.(false);
+ });
return () => {
abgebrochen = true;
@@ -46,8 +59,8 @@ function useBildUrl(productId, version = 0) {
* Rendert nichts, solange kein Bild vorliegt – ein leerer Rahmen neben einem
* Artikel, der nie ein Bild bekommen wird, wäre nur Lärm.
*/
-export default function ProduktBild({ productId, alt, className = "", version = 0 }) {
- const url = useBildUrl(productId, version);
+export default function ProduktBild({ productId, alt, className = "", version = 0, onLoaded }) {
+ const url = useBildUrl(productId, version, onLoaded);
if (!url) return null;
return ;
}
diff --git a/web/src/pages/ProductForm.jsx b/web/src/pages/ProductForm.jsx
index f97e5dd..8969d15 100644
--- a/web/src/pages/ProductForm.jsx
+++ b/web/src/pages/ProductForm.jsx
@@ -96,6 +96,8 @@ export default function ProductForm() {
const [offDaten, setOffDaten] = useState(null);
const [offBusy, setOffBusy] = useState(false);
const [bildVersion, setBildVersion] = useState(0);
+ // Ob gerade ein Bild vorliegt – steuert, ob „Entfernen" angeboten wird.
+ const [hatBild, setHatBild] = useState(false);
const selectedUnit = units.find((u) => String(u.id) === String(form.unit_id)) || null;
const unitFactor = selectedUnit ? selectedUnit.factor : 1;
@@ -561,7 +563,7 @@ export default function ProductForm() {
{!isNew && (