Skip to content

Interactive Registration

HTML:

<article>
  <small>Try entering an email that is already taken, such as trevinowanda@example.net (this is a mock email in our API)</small>
  <cami-registration-form></cami-registration-form>
</article>
<small>

</small>
<!-- CDN version below -->
<!-- <script src="https://unpkg.com/cami@latest/build/cami.cdn.js"></script> -->
<script type="module">
  const { html, ReactiveElement } = cami;

  class SignUpElement extends ReactiveElement {
    emailError = ''
    passwordError = ''
    email = '';
    password = '';
    emailIsValid = null;
    isEmailAvailable = null;

    inputValidation$ = this.stream();
    passwordValidation$ = this.stream();

    onConnect() {
      this.inputValidation$
        .map(e => this.validateEmail(e.target.value))
        .debounce(300)
        .subscribe(({ isEmailValid, emailError, email }) => {
          this.emailError = emailError;
          this.isEmailValid = isEmailValid;
          this.email = email;
          this.isEmailAvailable = this.queryEmail(this.email)
        });

      this.passwordValidation$
        .map(e => this.validatePassword(e.target.value))
        .debounce(300)
        .subscribe(({ isValid, password }) => {
          this.passwordError = isValid ? '' : 'Password must be at least 8 characters long.';
          this.password = password;
        });
    }

    validateEmail(email) {
      const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
      let emailError = '';
      let isEmailValid = null;
      if (email === '') {
        emailError = '';
        isEmailValid = null;
      } else if (!emailRegex.test(email)) {
        emailError = 'Please enter a valid email address.';
        isEmailValid = false;
      } else {
        emailError = '';
        isEmailValid = true;
      }
      return { isEmailValid, emailError, email };
    }

    validatePassword(password) {
      let isValid = false;
      if (password === '') {
        isValid = null;
      } else if (password?.length >= 8) {
        isValid = true;
      }

      return { isValid, password }
    }

    queryEmail(email) {
      return this.query({
        queryKey: ['Email', email],
        queryFn: () => {
          return fetch(`https://api.camijs.com/users?email=${email}`).then(res => res.json())
        },
        staleTime: 1000 * 60 * 5
      })
    }

    getEmailInputState() {
      if (this.email === '') {
        return '';
      } else if (this.isEmailValid && this.isEmailAvailable?.status === 'success' && this.isEmailAvailable?.data?.length === 0) {
        return false;
      } else {
        return true;
      }
    }

    getPasswordInputState() {
      if (this.password === '') {
        return '';
      } else if (this.passwordError === '') {
        return false;
      } else {
        return true;
      }
    }

    template() {
      return html`
        <form action="/submit" method="POST">
          <label>
            Email:
            <input type="email"
              aria-invalid=${this.getEmailInputState()}
              @input=${(e) => this.inputValidation$.next(e) } value=${this.email}>
              <span>${this.isEmailAvailable?.status === 'success' && this.isEmailAvailable?.data?.length > 0 && this.emailError === '' ? 'Email is already taken.' : ''}</span>
            <span>${this.emailError}</span>
          </label>
          <label>
            Password:
            <input type="password" @input=${(e) => this.passwordValidation$.next(e) }
              value=${this.password}
              aria-invalid=${this.getPasswordInputState()}>
            <span>${this.passwordError}</span>
          </label>
          <input type="submit" value="Submit" ?disabled=${this.emailError !== '' || this.passwordError !== '' || this.email === '' || this.password === ''}>
        </form>
      `;
    }
  }

  customElements.define('cami-registration-form', SignUpElement);
</script>