mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
Co-authored-by: Roo Code <roomote@roocode.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> Co-authored-by: Daniel <57051444+daniel-lxs@users.noreply.github.com>
112 lines
3.6 KiB
TypeScript
112 lines
3.6 KiB
TypeScript
import { useEffect, useRef } from "react"
|
|
import { FOLLOWUP_TIMEOUT_SECONDS } from "../../types/constants.js"
|
|
import { useUIStateStore } from "../stores/uiStateStore.js"
|
|
import type { PendingAsk } from "../types.js"
|
|
|
|
export interface UseFollowupCountdownOptions {
|
|
pendingAsk: PendingAsk | null
|
|
onAutoSubmit: (text: string) => void
|
|
}
|
|
|
|
/**
|
|
* Hook to manage auto-accept countdown timer for followup questions with suggestions.
|
|
*
|
|
* When a followup question appears with suggestions (and not in custom input mode),
|
|
* starts a countdown timer that auto-submits the first suggestion when it reaches zero.
|
|
*
|
|
* The countdown can be canceled by:
|
|
* - User navigating with arrow keys
|
|
* - User switching to custom input mode
|
|
* - Followup question changing/disappearing
|
|
*/
|
|
export function useFollowupCountdown({ pendingAsk, onAutoSubmit }: UseFollowupCountdownOptions) {
|
|
const { showCustomInput, countdownSeconds, setCountdownSeconds } = useUIStateStore()
|
|
const countdownIntervalRef = useRef<NodeJS.Timeout | null>(null)
|
|
|
|
// Use ref for onAutoSubmit to avoid stale closure issues without needing it in dependencies
|
|
const onAutoSubmitRef = useRef(onAutoSubmit)
|
|
useEffect(() => {
|
|
onAutoSubmitRef.current = onAutoSubmit
|
|
}, [onAutoSubmit])
|
|
|
|
// Cleanup interval on unmount
|
|
useEffect(() => {
|
|
return () => {
|
|
if (countdownIntervalRef.current) {
|
|
clearInterval(countdownIntervalRef.current)
|
|
}
|
|
}
|
|
}, [])
|
|
|
|
// Start countdown when a followup question with suggestions appears
|
|
useEffect(() => {
|
|
// Clear any existing countdown
|
|
if (countdownIntervalRef.current) {
|
|
clearInterval(countdownIntervalRef.current)
|
|
countdownIntervalRef.current = null
|
|
}
|
|
|
|
// Only start countdown for followup questions with suggestions (not custom input mode)
|
|
if (
|
|
pendingAsk?.type === "followup" &&
|
|
pendingAsk.suggestions &&
|
|
pendingAsk.suggestions.length > 0 &&
|
|
!showCustomInput
|
|
) {
|
|
// Start countdown
|
|
setCountdownSeconds(FOLLOWUP_TIMEOUT_SECONDS)
|
|
|
|
countdownIntervalRef.current = setInterval(() => {
|
|
const currentSeconds = useUIStateStore.getState().countdownSeconds
|
|
if (currentSeconds === null || currentSeconds <= 1) {
|
|
// Time's up! Auto-select first option
|
|
if (countdownIntervalRef.current) {
|
|
clearInterval(countdownIntervalRef.current)
|
|
countdownIntervalRef.current = null
|
|
}
|
|
setCountdownSeconds(null)
|
|
// Auto-submit the first suggestion
|
|
if (pendingAsk?.suggestions && pendingAsk.suggestions.length > 0) {
|
|
const firstSuggestion = pendingAsk.suggestions[0]
|
|
if (firstSuggestion) {
|
|
onAutoSubmitRef.current(firstSuggestion.answer)
|
|
}
|
|
}
|
|
} else {
|
|
setCountdownSeconds(currentSeconds - 1)
|
|
}
|
|
}, 1000)
|
|
} else {
|
|
// Only set to null if not already null to prevent unnecessary state updates
|
|
// This is critical to avoid infinite render loops
|
|
if (countdownSeconds !== null) {
|
|
setCountdownSeconds(null)
|
|
}
|
|
}
|
|
|
|
return () => {
|
|
if (countdownIntervalRef.current) {
|
|
clearInterval(countdownIntervalRef.current)
|
|
countdownIntervalRef.current = null
|
|
}
|
|
}
|
|
// Note: countdownSeconds is intentionally NOT in deps - we only read it to avoid
|
|
// unnecessary state updates, not to react to its changes
|
|
}, [pendingAsk?.id, pendingAsk?.type, showCustomInput, setCountdownSeconds])
|
|
|
|
/**
|
|
* Cancel the countdown timer (called when user interacts with the menu)
|
|
*/
|
|
const cancelCountdown = () => {
|
|
if (countdownIntervalRef.current) {
|
|
clearInterval(countdownIntervalRef.current)
|
|
countdownIntervalRef.current = null
|
|
}
|
|
setCountdownSeconds(null)
|
|
}
|
|
|
|
return {
|
|
countdownSeconds,
|
|
cancelCountdown,
|
|
}
|
|
}
|