import { useCallback, useEffect, useState } from "react" import { ClipboardCopy, Timer } from "lucide-react" import { Button, StandardTooltip } from "@/components/ui" import { useAppTranslation } from "@src/i18n/TranslationContext" import { useExtensionState } from "@src/context/ExtensionStateContext" import { SuggestionItem } from "@roo-code/types" import { cn } from "@/lib/utils" const DEFAULT_FOLLOWUP_TIMEOUT_MS = 60000 const COUNTDOWN_INTERVAL_MS = 1000 interface FollowUpSuggestProps { suggestions?: SuggestionItem[] onSuggestionClick?: (suggestion: SuggestionItem, event?: React.MouseEvent) => void ts: number onCancelAutoApproval?: () => void isAnswered?: boolean isFollowUpAutoApprovalPaused?: boolean } export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1, onCancelAutoApproval, isAnswered = false, isFollowUpAutoApprovalPaused = false, }: FollowUpSuggestProps) => { const { autoApprovalEnabled, alwaysAllowFollowupQuestions, followupAutoApproveTimeoutMs } = useExtensionState() const [countdown, setCountdown] = useState(null) const [suggestionSelected, setSuggestionSelected] = useState(false) const { t } = useAppTranslation() // Start countdown timer when auto-approval is enabled for follow-up questions useEffect(() => { // Only start countdown if auto-approval is enabled for follow-up questions and no suggestion has been selected // Also stop countdown if the question has been answered or auto-approval is paused (user is typing) if ( autoApprovalEnabled && alwaysAllowFollowupQuestions && suggestions.length > 0 && !suggestionSelected && !isAnswered && !isFollowUpAutoApprovalPaused ) { // Start with the configured timeout in seconds const timeoutMs = typeof followupAutoApproveTimeoutMs === "number" && !isNaN(followupAutoApproveTimeoutMs) ? followupAutoApproveTimeoutMs : DEFAULT_FOLLOWUP_TIMEOUT_MS // Convert milliseconds to seconds for the countdown setCountdown(Math.floor(timeoutMs / 1000)) // Update countdown every second const intervalId = setInterval(() => { setCountdown((prevCountdown) => { if (prevCountdown === null || prevCountdown <= 1) { clearInterval(intervalId) return null } return prevCountdown - 1 }) }, COUNTDOWN_INTERVAL_MS) // Clean up interval on unmount and notify parent component return () => { clearInterval(intervalId) // Notify parent component that this component is unmounting // so it can clear any related timeouts onCancelAutoApproval?.() } } else { setCountdown(null) } }, [ autoApprovalEnabled, alwaysAllowFollowupQuestions, suggestions, followupAutoApproveTimeoutMs, suggestionSelected, onCancelAutoApproval, isAnswered, isFollowUpAutoApprovalPaused, ]) const handleSuggestionClick = useCallback( (suggestion: SuggestionItem, event: React.MouseEvent) => { // Mark a suggestion as selected if it's not a shift-click (which just copies to input) if (!event.shiftKey) { setSuggestionSelected(true) // Also notify parent component to cancel auto-approval timeout // This prevents race conditions between visual countdown and actual timeout onCancelAutoApproval?.() } // Pass the suggestion object to the parent component // The parent component will handle mode switching if needed onSuggestionClick?.(suggestion, event) }, [onSuggestionClick, onCancelAutoApproval], ) // Don't render if there are no suggestions or no click handler. if (!suggestions?.length || !onSuggestionClick) { return null } return (
{suggestions.map((suggestion, index) => { const isFirstSuggestion = index === 0 return (
{isFirstSuggestion && countdown !== null && !suggestionSelected && !isAnswered && (

{t("chat:followUpSuggest.timerPrefix", { seconds: countdown })}

)} {suggestion.mode && (
{suggestion.mode}
)}
{ e.stopPropagation() // Cancel the auto-approve timer when edit button is clicked setSuggestionSelected(true) onCancelAutoApproval?.() // Simulate shift-click by directly calling the handler with shiftKey=true. onSuggestionClick?.(suggestion, { ...e, shiftKey: true }) }}>
) })}
) }