From af74228f8e141a40722b64a99ea6be6b03ba72f0 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Fri, 27 May 2022 10:37:27 -0400 Subject: [PATCH] TypeScriptify useRecaptcha --- package.json | 3 +- src/auth/{useRecaptcha.js => useRecaptcha.ts} | 59 +++++++++---------- yarn.lock | 5 ++ 3 files changed, 34 insertions(+), 33 deletions(-) rename src/auth/{useRecaptcha.js => useRecaptcha.ts} (72%) diff --git a/package.json b/package.json index fbfcfb24..e50037f5 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "build-storybook": "build-storybook", "prettier:check": "prettier -c src", "prettier:format": "prettier -w src", - "lint:js": "eslint --max-warnings 2 src", + "lint:js": "eslint --max-warnings 0 src", "lint:types": "tsc" }, "dependencies": { @@ -31,6 +31,7 @@ "@react-stately/tree": "^3.2.0", "@sentry/react": "^6.13.3", "@sentry/tracing": "^6.13.3", + "@types/grecaptcha": "^3.0.4", "@use-gesture/react": "^10.2.11", "classnames": "^2.3.1", "color-hash": "^2.0.1", diff --git a/src/auth/useRecaptcha.js b/src/auth/useRecaptcha.ts similarity index 72% rename from src/auth/useRecaptcha.js rename to src/auth/useRecaptcha.ts index 41710bd6..76856a23 100644 --- a/src/auth/useRecaptcha.js +++ b/src/auth/useRecaptcha.ts @@ -14,52 +14,49 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { randomString } from "matrix-js-sdk/src/randomstring"; import { useEffect, useCallback, useRef, useState } from "react"; +import { randomString } from "matrix-js-sdk/src/randomstring"; + +declare global { + interface Window { + mxOnRecaptchaLoaded: () => void; + } +} const RECAPTCHA_SCRIPT_URL = "https://www.recaptcha.net/recaptcha/api.js?onload=mxOnRecaptchaLoaded&render=explicit"; -export function useRecaptcha(sitekey) { +interface RecaptchaPromiseRef { + resolve: (response: string) => void; + reject: (error: Error) => void; +} + +export const useRecaptcha = (sitekey: string) => { const [recaptchaId] = useState(() => randomString(16)); - const promiseRef = useRef(); + const promiseRef = useRef(); useEffect(() => { - if (!sitekey) { - return; - } + if (!sitekey) return; const onRecaptchaLoaded = () => { - if (!document.getElementById(recaptchaId)) { - return; - } + if (!document.getElementById(recaptchaId)) return; window.grecaptcha.render(recaptchaId, { sitekey, size: "invisible", - callback: (response) => { - if (promiseRef.current) { - promiseRef.current.resolve(response); - } - }, - "error-callback": (error) => { - if (promiseRef.current) { - promiseRef.current.reject(error); - } - }, + callback: (response: string) => promiseRef.current?.resolve(response), + // eslint-disable-next-line @typescript-eslint/naming-convention + "error-callback": () => promiseRef.current?.reject(new Error()), }); }; - if ( - typeof window.grecaptcha !== "undefined" && - typeof window.grecaptcha.render === "function" - ) { + if (typeof window.grecaptcha?.render === "function") { onRecaptchaLoaded(); } else { window.mxOnRecaptchaLoaded = onRecaptchaLoaded; if (!document.querySelector(`script[src="${RECAPTCHA_SCRIPT_URL}"]`)) { - const scriptTag = document.createElement("script"); + const scriptTag = document.createElement("script") as HTMLScriptElement; scriptTag.src = RECAPTCHA_SCRIPT_URL; scriptTag.async = true; document.body.appendChild(scriptTag); @@ -80,7 +77,7 @@ export function useRecaptcha(sitekey) { return new Promise((resolve, reject) => { const observer = new MutationObserver((mutationsList) => { for (const item of mutationsList) { - if (item.target?.style?.visibility !== "visible") { + if ((item.target as HTMLElement)?.style?.visibility !== "visible") { reject(new Error("Recaptcha dismissed")); observer.disconnect(); return; @@ -101,7 +98,7 @@ export function useRecaptcha(sitekey) { window.grecaptcha.execute(); - const iframe = document.querySelector( + const iframe = document.querySelector( 'iframe[src*="recaptcha/api2/bframe"]' ); @@ -111,13 +108,11 @@ export function useRecaptcha(sitekey) { }); } }); - }, [recaptchaId, sitekey]); + }, [sitekey]); const reset = useCallback(() => { - if (window.grecaptcha) { - window.grecaptcha.reset(); - } - }, [recaptchaId]); + window.grecaptcha?.reset(); + }, []); return { execute, reset, recaptchaId }; -} +}; diff --git a/yarn.lock b/yarn.lock index 74d88f48..c95df5b7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2876,6 +2876,11 @@ "@types/minimatch" "*" "@types/node" "*" +"@types/grecaptcha@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/grecaptcha/-/grecaptcha-3.0.4.tgz#3de601f3b0cd0298faf052dd5bd62aff64c2be2e" + integrity sha512-7l1Y8DTGXkx/r4pwU1nMVAR+yD/QC+MCHKXAyEX/7JZhwcN1IED09aZ9vCjjkcGdhSQiu/eJqcXInpl6eEEEwg== + "@types/hast@^2.0.0": version "2.3.4" resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.4.tgz#8aa5ef92c117d20d974a82bdfb6a648b08c0bafc"