Files
certain/web/src/toast.jsx
T
GuidoandClaude Opus 5 8cb82da63c fix: Uebertrag buchen tat sichtbar nichts – useToast falsch ausgepackt
useToast() liefert die Melde-Funktion selbst, kein Objekt. In drei Dateien aus
dieser Sitzung stand "const { toast } = useToast()", also undefined. Der Aufruf
steht fast immer in einem catch – dort verschluckt der TypeError die
eigentliche Meldung, und nach aussen passiert gar nichts.

Das erklaert beide Beschwerden:

- "Als Uebertrag buchen" schien wirkungslos: Die Buchung lief durch, dann warf
  toast(), der catch warf beim Melden erneut, der Dialog blieb offen.
- "Braucht ein Reload": Im Eingang stand toast() VOR laden() – der Dialog
  schloss noch, das Neuladen kam nie. Die Cache-Kopfzeile, die ich dafuer
  gesetzt habe, war nicht die Ursache; richtig ist sie trotzdem.

Am Ende in der laufenden Oberflaeche nachgeklickt: Dialog schliesst, Meldung
erscheint, die Zeile wird ohne Neuladen zum Uebertrag, die Gegenseite liegt auf
dem Zielkonto, beide Salden stimmen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 11:15:43 +02:00

74 lines
2.5 KiB
React
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { createContext, useCallback, useContext, useEffect, useRef, useState } from "react";
import Icon from "./components/Icon";
/**
* Kurze Rückmeldungen als Overlay am unteren Rand.
*
* Vorher standen sie als Hinweisleiste mitten in der Seite – dadurch sprang
* beim Speichern das ganze Layout ein Stück nach unten. Ein Overlay liegt über
* dem Inhalt und verschiebt nichts.
*
* Bewusst nur für *Erfolgsmeldungen*: Fehler bleiben als Leiste an ihrer Stelle
* stehen. Eine Fehlermeldung, die nach fünf Sekunden verschwindet, ist genau
* dann weg, wenn man sie noch braucht.
*
* const toast = useToast();
* toast("Gespeichert.");
*/
const ToastContext = createContext(() => {});
const DAUER = 5000;
export function ToastProvider({ children }) {
const [meldungen, setMeldungen] = useState([]);
const uhren = useRef(new Map());
const entfernen = useCallback((id) => {
setMeldungen((alt) => alt.filter((m) => m.id !== id));
const uhr = uhren.current.get(id);
if (uhr) {
clearTimeout(uhr);
uhren.current.delete(id);
}
}, []);
const zeigen = useCallback((text, art = "ok") => {
if (!text) return;
const id = `${Date.now()}-${Math.random()}`;
setMeldungen((alt) => [...alt, { id, text, art }]);
uhren.current.set(id, setTimeout(() => entfernen(id), DAUER));
}, [entfernen]);
// Beim Verlassen der Seite laufende Uhren abräumen.
useEffect(() => {
const laufend = uhren.current;
return () => laufend.forEach((uhr) => clearTimeout(uhr));
}, []);
return (
<ToastContext.Provider value={zeigen}>
{children}
{/* aria-live: Bildschirmleser sagen die Meldung an, ohne den Fokus zu stehlen. */}
<div className="toasts" role="status" aria-live="polite">
{meldungen.map((m) => (
<div key={m.id} className={`toast ${m.art}`}>
<Icon name={m.art === "ok" ? "check" : "alert"} size={16} />
<span className="toast-text">{m.text}</span>
<button className="btn-icon" onClick={() => entfernen(m.id)} title="Ausblenden">
<Icon name="close" size={15} />
</button>
</div>
))}
</div>
</ToastContext.Provider>
);
}
// Liefert die Melde-Funktion SELBST, nicht ein Objekt mit ihr darin.
// `const { toast } = useToast()` ergibt undefined – und weil der Aufruf fast
// immer in einem catch steht, verschluckt der TypeError dort die eigentliche
// Meldung und es passiert sichtbar gar nichts.
export function useToast() {
return useContext(ToastContext);
}