CardioScreen AI commited on
Commit
8f78b71
Β·
1 Parent(s): 4a627f0

fix: React hooks order violation (useState before useEffect)

Browse files
Files changed (1) hide show
  1. webapp/src/App.jsx +13 -9
webapp/src/App.jsx CHANGED
@@ -399,6 +399,7 @@ function AudioTrimmer({ waveform, duration, onAnalyze, onSkip }) {
399
  const API_URL = (import.meta.env.VITE_API_URL) ?? "http://127.0.0.1:8000/analyze";
400
 
401
  function App() {
 
402
  const [appState, setAppState] = useState('upload');
403
  const [patientData, setPatientData] = useState({ dogId: '', breed: '', age: '' });
404
  const [analysisResult, setAnalysisResult] = useState(null);
@@ -406,19 +407,14 @@ function App() {
406
  const [recordingTime, setRecordingTime] = useState(0);
407
  const [audioBlob, setAudioBlob] = useState(null);
408
  const [audioUrl, setAudioUrl] = useState(null);
 
 
409
  const [theme, setTheme] = useState('dark');
410
  const [mobileNavOpen, setMobileNavOpen] = useState(false);
411
 
412
- // Apply theme to <html> element
413
- useEffect(() => {
414
- document.documentElement.setAttribute('data-theme', theme);
415
- }, [theme]);
416
 
417
- const toggleTheme = () => setTheme(t => t === 'dark' ? 'light' : 'dark');
418
- const closeMobileNav = () => setMobileNavOpen(false);
419
- const [trimWaveform, setTrimWaveform] = useState(null);
420
- const [trimDuration, setTrimDuration] = useState(0);
421
- const rawAudioBuffer = useRef(null); // holds decoded AudioBuffer for trimming
422
 
423
  const audioContextRef = useRef(null);
424
  const analyserRef = useRef(null);
@@ -432,6 +428,14 @@ function App() {
432
  const waveformCanvasRef = useRef(null);
433
  const audioRef = useRef(null);
434
 
 
 
 
 
 
 
 
 
435
  const stopRecording = () => {
436
  if (mediaRecorderRef.current && mediaRecorderRef.current.state !== 'inactive') {
437
  mediaRecorderRef.current.stop();
 
399
  const API_URL = (import.meta.env.VITE_API_URL) ?? "http://127.0.0.1:8000/analyze";
400
 
401
  function App() {
402
+ // ── All useState hooks first (React rules of hooks) ──────
403
  const [appState, setAppState] = useState('upload');
404
  const [patientData, setPatientData] = useState({ dogId: '', breed: '', age: '' });
405
  const [analysisResult, setAnalysisResult] = useState(null);
 
407
  const [recordingTime, setRecordingTime] = useState(0);
408
  const [audioBlob, setAudioBlob] = useState(null);
409
  const [audioUrl, setAudioUrl] = useState(null);
410
+ const [trimWaveform, setTrimWaveform] = useState(null);
411
+ const [trimDuration, setTrimDuration] = useState(0);
412
  const [theme, setTheme] = useState('dark');
413
  const [mobileNavOpen, setMobileNavOpen] = useState(false);
414
 
415
+ // ── All useRef hooks next ─────────────────────────────────
416
+ const rawAudioBuffer = useRef(null);
 
 
417
 
 
 
 
 
 
418
 
419
  const audioContextRef = useRef(null);
420
  const analyserRef = useRef(null);
 
428
  const waveformCanvasRef = useRef(null);
429
  const audioRef = useRef(null);
430
 
431
+ // Apply theme attribute to <html> element
432
+ useEffect(() => {
433
+ document.documentElement.setAttribute('data-theme', theme);
434
+ }, [theme]);
435
+
436
+ const toggleTheme = () => setTheme(t => t === 'dark' ? 'light' : 'dark');
437
+ const closeMobileNav = () => setMobileNavOpen(false);
438
+
439
  const stopRecording = () => {
440
  if (mediaRecorderRef.current && mediaRecorderRef.current.state !== 'inactive') {
441
  mediaRecorderRef.current.stop();