From 5d79dc8c413cc544650c73e91fdec053abf421da Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Mon, 28 Jul 2025 14:27:50 +0300 Subject: [PATCH] docs: handle recaptcha loading before submitting AI assistant queries (#13065) --- .../AiAssistant/ChatWindow/Input/index.tsx | 26 ++++++++++--------- .../src/providers/AiAssistant/index.tsx | 20 ++++++++++++++ 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/www/packages/docs-ui/src/components/AiAssistant/ChatWindow/Input/index.tsx b/www/packages/docs-ui/src/components/AiAssistant/ChatWindow/Input/index.tsx index 02300ef9ed..e77b934cb3 100644 --- a/www/packages/docs-ui/src/components/AiAssistant/ChatWindow/Input/index.tsx +++ b/www/packages/docs-ui/src/components/AiAssistant/ChatWindow/Input/index.tsx @@ -12,7 +12,8 @@ type AiAssistantChatWindowInputProps = { export const AiAssistantChatWindowInput = ({ chatWindowRef, }: AiAssistantChatWindowInputProps) => { - const { chatOpened, inputRef, loading, setChatOpened } = useAiAssistant() + const { chatOpened, inputRef, loading, setChatOpened, isCaptchaLoaded } = + useAiAssistant() const { submitQuery, conversation } = useChat() const { isBrowser } = useIsBrowser() const { searchQuery, searchQueryType } = useMemo(() => { @@ -29,9 +30,12 @@ export const AiAssistantChatWindowInput = ({ const [question, setQuestion] = React.useState("") const formRef = useRef(null) - const onSubmit = (e?: React.FormEvent) => { + const onSubmit = ( + e?: React.FormEvent, + overrideQuestion?: string + ) => { e?.preventDefault() - submitQuery(question) + submitQuery(overrideQuestion || question) setQuestion("") } @@ -110,19 +114,17 @@ export const AiAssistantChatWindowInput = ({ }) useEffect(() => { - if (searchQueryType === "submit") { - onSubmit() - } - }, [searchQueryType]) - - useEffect(() => { - if (!searchQuery) { + if (!searchQuery || !isCaptchaLoaded) { return } setQuestion(searchQuery) setChatOpened(true) - }, [searchQuery]) + if (searchQueryType !== "submit") { + return + } + onSubmit(undefined, searchQuery) + }, [searchQuery, searchQueryType, isCaptchaLoaded]) return (
diff --git a/www/packages/docs-ui/src/providers/AiAssistant/index.tsx b/www/packages/docs-ui/src/providers/AiAssistant/index.tsx index b36d68b955..df4841100e 100644 --- a/www/packages/docs-ui/src/providers/AiAssistant/index.tsx +++ b/www/packages/docs-ui/src/providers/AiAssistant/index.tsx @@ -24,6 +24,7 @@ export type AiAssistantContextType = { inputRef: React.RefObject contentRef: React.RefObject loading: boolean + isCaptchaLoaded: boolean } export type AiAssistantThreadItem = { @@ -59,6 +60,7 @@ const AiAssistantInnerProvider = ({ setOnCompleteAction, type, }: AiAssistantInnerProviderProps) => { + const [isCaptchaLoaded, setIsCaptchaLoaded] = useState(false) const [chatOpened, setChatOpened] = useState(false) const inputRef = useRef(null) const contentRef = useRef(null) @@ -146,6 +148,23 @@ const AiAssistantInnerProvider = ({ const recaptchaElm = document.querySelector(".grecaptcha-badge") recaptchaElm?.parentElement?.classList.add("absolute") + const maxRetry = 10 + let retries = 0 + const interval = setInterval(() => { + if (window.grecaptcha) { + setIsCaptchaLoaded(true) + clearInterval(interval) + return + } + retries++ + if (retries > maxRetry) { + clearInterval(interval) + } + }, 1000) + + return () => { + clearInterval(interval) + } }, [isBrowser]) return ( @@ -157,6 +176,7 @@ const AiAssistantInnerProvider = ({ inputRef, contentRef, loading, + isCaptchaLoaded, }} > {children}