de7fdb7377
Gemessene Ursache des Wackeltests aus CI-Lauf 395, und es ist ein Produktfehler, kein Testfehler. Ein MutationObserver ueber jeden DOM-Commit beim Oeffnen protokollierte: COMMIT dialog=true img=ja box=AUS <- falsch, aber festgeschrieben COMMIT dialog=true img=ja box=AN Der erste Zustand entstand bei JEDEM Oeffnen, nicht nur unter Last, und hielt ohne act() zwei volle Makrotask-Runden - der Browser hat in dieser Zeit mindestens zwei Gelegenheiten, ihn zu zeichnen. Ein Nutzer sieht also sein Vorschaubild kurz mit ausgeschaltetem Haekchen. Der Test fiel nur dann durch, wenn er zufaellig den ersten statt den zweiten Commit sah; die Last im vollen Lauf war der Ausloeser, nicht die Ursache. Zwei Bedingungen mussten zusammentreffen. Erstens war der Dialog dauerhaft eingehaengt und gab bei geschlossenem Zustand nur null zurueck - useState(screenshot !== null) lief damit ein einziges Mal, beim allerersten Mount des Knopfs, als noch gar kein Bild da war. Das Haekchen startete also immer aus. Zweitens zog ein useEffect den Zustand nach, und passive Effekte laufen erst NACH dem Commit. Beides ist jetzt weg. Der Dialog wird nur noch eingehaengt, solange er offen ist, also ist jedes Oeffnen ein frischer Mount mit frischem Zustand. Und das Haekchen wird beim Rendern aus screenshot abgeleitet statt per Effekt nachgezogen; attachChoice haelt allein die bewusste Abwahl des Nutzers. Der Effekt, der Status, Text und Haekchen beim Oeffnen zuruecksetzte, entfaellt ersatzlos. Damit verschwindet dieselbe Klasse an einer zweiten Stelle: beim erneuten Oeffnen nach einem Versand stand bisher zwei Runden lang der alte Danke-Bildschirm im DOM, bevor das frische Formular erschien. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J
77 lines
2.8 KiB
TypeScript
77 lines
2.8 KiB
TypeScript
'use client';
|
|
|
|
import { useTranslations } from 'next-intl';
|
|
import { useState } from 'react';
|
|
import { captureScreenshot } from '@/lib/bug-report-api';
|
|
import { useAuthStore } from '@/lib/stores/auth-store';
|
|
import { BugReportDialog } from './bug-report-dialog';
|
|
|
|
/**
|
|
* Fehler-melden-Knopf in der Kopfzeile (quick-260914-m97), Stil wie
|
|
* `ThemeToggle`. Kernanforderung: das Bild der Seite wird aufgenommen,
|
|
* BEVOR der Dialog erscheint — sonst waere der Dialog im Bild.
|
|
*/
|
|
export function BugReportButton() {
|
|
const t = useTranslations('bugReport');
|
|
const user = useAuthStore((s) => s.user);
|
|
const isAdmin = user?.role === 'ADMIN' || user?.role === 'SUPER_ADMIN';
|
|
const [capturing, setCapturing] = useState(false);
|
|
const [open, setOpen] = useState(false);
|
|
const [screenshot, setScreenshot] = useState<string | null>(null);
|
|
|
|
const handleClick = async () => {
|
|
if (capturing) return;
|
|
setCapturing(true);
|
|
// Reihenfolge ist die Kernanforderung: erst aufnehmen, dann oeffnen.
|
|
const shot = await captureScreenshot();
|
|
setScreenshot(shot);
|
|
setOpen(true);
|
|
setCapturing(false);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<button
|
|
type="button"
|
|
onClick={handleClick}
|
|
className="inline-flex items-center justify-center rounded-md p-2 text-muted-foreground hover:bg-muted hover:text-foreground transition-colors disabled:opacity-50"
|
|
aria-label={t('button')}
|
|
title={t('button')}
|
|
disabled={capturing}
|
|
data-bug-report-ignore="true"
|
|
>
|
|
{/* Kaefer-Symbol nach dem lucide-Symbol "bug" */}
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
width="20"
|
|
height="20"
|
|
viewBox="0 0 24 24"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
strokeWidth="2"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
aria-hidden="true"
|
|
>
|
|
<path d="m8 2 1.88 1.88" />
|
|
<path d="M14.12 3.88 16 2" />
|
|
<path d="M9 7.13v-1a3.003 3.003 0 1 1 6 0v1" />
|
|
<path d="M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v3c0 3.3-2.7 6-6 6" />
|
|
<path d="M12 20v-9" />
|
|
<path d="M6.53 9C4.6 8.8 3 7.1 3 5" />
|
|
<path d="M6 13H2" />
|
|
<path d="M3 21c0-2.1 1.7-3.9 3.8-4" />
|
|
<path d="M20.97 5c0 2.1-1.6 3.8-3.5 4" />
|
|
<path d="M22 13h-4" />
|
|
<path d="M17.2 17c2.1.1 3.8 1.9 3.8 4" />
|
|
</svg>
|
|
</button>
|
|
{/* Nur eingehaengt, solange offen (quick-260921-ldf): so startet jedes
|
|
Oeffnen mit frischem Zustand — Haekchen, Text und Status stimmen
|
|
schon im ersten Commit, statt einen Commit spaeter nachgezogen zu
|
|
werden. */}
|
|
{open && <BugReportDialog screenshot={screenshot} isAdmin={isAdmin} onClose={() => setOpen(false)} />}
|
|
</>
|
|
);
|
|
}
|