18F/identity-idp

View on GitHub
app/javascript/packages/captcha-submit-button/captcha-submit-button-element.ts

Summary

Maintainability
A
0 mins
Test Coverage
class CaptchaSubmitButtonElement extends HTMLElement {
  form: HTMLFormElement | null;

  connectedCallback() {
    this.form = this.closest('form');

    this.form?.addEventListener('submit', this.handleFormSubmit);
  }

  disconnectedCallback() {
    this.form?.removeEventListener('submit', this.handleFormSubmit);
  }

  get button(): HTMLButtonElement {
    return this.querySelector('button')!;
  }

  get tokenInput(): HTMLInputElement {
    return this.querySelector('[type=hidden]')!;
  }

  get recaptchaSiteKey(): string | null {
    return this.getAttribute('recaptcha-site-key');
  }

  get recaptchaAction(): string {
    return this.getAttribute('recaptcha-action')!;
  }

  get isRecaptchaEnterprise(): boolean {
    return this.getAttribute('recaptcha-enterprise') === 'true';
  }

  get recaptchaClient(): ReCaptchaV2.ReCaptcha | undefined {
    if (this.isRecaptchaEnterprise) {
      return globalThis.grecaptcha?.enterprise;
    }

    return globalThis.grecaptcha;
  }

  submit() {
    this.form?.submit();
  }

  invokeChallenge() {
    this.recaptchaClient!.ready(async () => {
      const { recaptchaSiteKey: siteKey, recaptchaAction: action } = this;
      const token = await this.recaptchaClient!.execute(siteKey!, { action });
      this.tokenInput.value = token;
      this.submit();
    });
  }

  shouldInvokeChallenge(): boolean {
    return !!(this.recaptchaSiteKey && this.recaptchaClient);
  }

  handleFormSubmit = (event: SubmitEvent) => {
    if (this.shouldInvokeChallenge()) {
      event.preventDefault();
      this.invokeChallenge();
    }
  };
}

declare global {
  interface HTMLElementTagNameMap {
    'lg-captcha-submit-button': CaptchaSubmitButtonElement;
  }
}

if (!customElements.get('lg-captcha-submit-button')) {
  customElements.define('lg-captcha-submit-button', CaptchaSubmitButtonElement);
}

export default CaptchaSubmitButtonElement;