TypeScriptify useRecaptcha
This commit is contained in:
		
					parent
					
						
							
								9a44790450
							
						
					
				
			
			
				commit
				
					
						af74228f8e
					
				
			
		
					 3 changed files with 34 additions and 33 deletions
				
			
		| 
						 | 
				
			
			@ -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",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<RecaptchaPromiseRef>();
 | 
			
		||||
 | 
			
		||||
  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<HTMLIFrameElement>(
 | 
			
		||||
        '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 };
 | 
			
		||||
}
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -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"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue