/** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import { useState, useEffect, useRef } from 'react'; import { WITTY_LOADING_PHRASES, PHRASE_CHANGE_INTERVAL_MS, } from '../constants.js'; import { StreamingState } from '../types.js'; export const useLoadingIndicator = (streamingState: StreamingState) => { const [elapsedTime, setElapsedTime] = useState(0); const [currentLoadingPhrase, setCurrentLoadingPhrase] = useState( WITTY_LOADING_PHRASES[0], ); const timerRef = useRef(null); const phraseIntervalRef = useRef(null); const currentPhraseIndexRef = useRef(0); // Timer effect for elapsed time during loading useEffect(() => { if (streamingState === StreamingState.Responding) { setElapsedTime(0); // Reset timer on new loading start timerRef.current = setInterval(() => { setElapsedTime((prevTime) => prevTime + 1); }, 1000); } else if (timerRef.current) { clearInterval(timerRef.current); timerRef.current = null; } // Cleanup on unmount or when isLoading changes return () => { if (timerRef.current) { clearInterval(timerRef.current); } }; }, [streamingState]); // Effect for cycling through witty loading phrases useEffect(() => { if (streamingState === StreamingState.Responding) { currentPhraseIndexRef.current = 0; setCurrentLoadingPhrase(WITTY_LOADING_PHRASES[0]); phraseIntervalRef.current = setInterval(() => { currentPhraseIndexRef.current = (currentPhraseIndexRef.current + 1) % WITTY_LOADING_PHRASES.length; setCurrentLoadingPhrase( WITTY_LOADING_PHRASES[currentPhraseIndexRef.current], ); }, PHRASE_CHANGE_INTERVAL_MS); } else if (phraseIntervalRef.current) { clearInterval(phraseIntervalRef.current); phraseIntervalRef.current = null; } // Cleanup on unmount or when isLoading changes return () => { if (phraseIntervalRef.current) { clearInterval(phraseIntervalRef.current); } }; }, [streamingState]); return { elapsedTime, currentLoadingPhrase }; };