JSFiddle - React, Tailwind, and code Playground

Authentication UI - PAA

by Hugo Carneiro

HTML

<div class="viewport-content scroll">
  <div class="content-main container-fluid">
    <div class="row">
      <div class="col-xs-12 col-md-8 col-md-offset-2">
        <!-- USE HTML FROM HERE ONLY -->
        <div class="content-wrapper">
          <div class="state start" data-state="auth">
            <h1>Welcome to PAA Alliance app</h1>
            <p>Authenticate your email address below to gain access to the app.</p>
            <div class="form-group">
              <input type="email" name="verify-email" class="form-control" id="verify_email" placeholder="Enter your email">
              <p class="email-error">Please enter a valid email.</p>
            </div>
            <button class="buttonControl ui-button link-button-primary verify-identity" id="">Authenticate</button>
            <button class="buttonControl ui-button link-text have-code">I already have a pin code</button>
          </div>

          <div class="state future" data-state="verify-code">
            <h2>Verify your email address</h2>
            <p>Enter the pin code that was sent to <span id="input-email">[email protected]</span>.</p>
            <div class="form-group input-wrapper">
              <input type="text" id="verify_pin" class="form-control" placeholder="Enter pin code" />
              <span class="glyphicon glyphicon-chevron-left back"></span>
              <p class="pin-error">You entered the wrong pin code or it might have expired.<br>Try again or tap <i>Resend pin code</i>.</p>
            </div>

            <button class="buttonControl ui-button link-button-primary verify-code">Verify</button>
            <button class="buttonControl ui-button link-text resend-code">Resend pin code</button>
            <p class="pin-resent text-success">A new pin code was sent to your email.</p>
          </div>

          <div class="state future" data-state="confirmation">
            <h1>Welcome to PAA Alliance app</h1>
            <p>You have been authenticated and you can...

CSS

body {
  background: #e8e8e8;
  color: #333;
}

.viewport-content {
  padding-top: 44px;
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}

.scroll {
  overflow: auto !important;
}

.content-main {
  padding-top: 70px;
}

.ui-button {
  cursor: pointer;
}

.ui-button,
.link-button-primary {
  padding: 10px 16px;
  font-size: 18px;
  line-height: 1.33;
  border: none;
  border-radius: 0px;
  text-align: center;
  clear: none;
  display: block;
  width: auto;
  max-width: 100%;
  font-weight: 200;
}

.ui-button,
.link-button-primary {
  color: #FFF;
  background-color: #0088cc;
}

.link-text,
.ui-button.link-text {
  text-decoration: underline;
  display: inline;
  width: auto;
  font-size: 1em;
  line-height: inherit;
  padding: 0;
  text-align: inherit;
  border: inherit;
  border-radius: inherit;
  background: none;
}

.link-text {
  color: #00AEEF;
}

/* USE CSS FROM HERE ONLY */

.content-wrapper {
  position: relative;
  overflow: hidden;
  margin-bottom: 30px;
}

.content-wrapper .state {
  position: absolute;
  width: 100%;
  text-align: center;
  opacity: 0;
  pointer-events: none;
  -webkit-transform: translate3d(0, 0, 0);
  transform: translate3d(0, 0, 0);
}

.content-wrapper .state.past {
  -webkit-transform: translate3d(-105%, 0, 0);
  transform: translate3d(-105%, 0, 0);
  -webkit-transition: all 0.25s ease;
  transition: all 0.25s ease;
}

.content-wrapper .state.present {
  opacity: 1;
  pointer-events: all;
  -webkit-transition: all 0.25s ease;
  transition: all 0.25s ease;
}

.content-wrapper .state.future {
  -webkit-transform: translate3d(105%, 0, 0);
  transform: translate3d(105%, 0, 0);
  -webkit-transition: all 0.25s ease;
  transition: all 0.25s ease;
}

.state p {
  margin: 30px 0 20px 0;
}

.state p + p {
  margin: -10px 0 20px 0;
}

.state .input-wrapper {
  position: relative;
}

.state .back {
  position: absolute;
  top: 2px;
  left: 0;
  z-index: 1;
  height: 51px;
  line-height: 51px;
  width: 40px;
  color:...

JavaScript

// DATA SOURCE REPLICA
userData = {
  columns: {
    0: "Email",
    1: "Name",
    2: "Status"
  },
  rows: {
    0: {
      Email: "[email protected]",
      Name: "Hugo Carneiro",
      Status: "Inactive"
    },
    1: {
      Email: "[email protected]",
      Name: "Tony Wu",
      Status: "Inactive"
    }
  }
}

// INITIATE FUNCTIONS
function calculateElHeight(el) {

  var elementHeight = el.outerHeight();
  
  if (el.hasClass('start')) {
  	if (havePinCode) {
    	$('.state[data-state=auth]').addClass('has-code');
    }
    $('.state[data-state=auth]').removeClass('start').addClass('present');
  }
  
	el.parents('.content-wrapper').css({'height' : elementHeight, 'opacity' : '0'}).css('opacity', '1'); // Opcaity added to prevent render issues on less capable devices
}

function onlineCheck() {
  if (offline) {
    $('#offline-notification').addClass('show');
    $('body').addClass('device-offline');
  } else {
    if ($('#offline-notification').hasClass('show')) {
      $('#offline-notification').removeClass('show');
    }
    if ($('body').hasClass('device-offline')){
    	$('body').removeClass('device-offline');
    }
  }
}

function checkAuth(email) {
  for (var key in userData.rows) {
    // Skip loop if the property is from prototype
    if (!userData.rows.hasOwnProperty(key)) continue;

    var obj = userData.rows[key];
    for (var prop in obj) {
      // Skip loop if the property is from prototype
      if (!obj.hasOwnProperty(prop)) continue;

      // Checks if email address is found
      if (email === obj[prop]) {
        return true;
      }
    }
  }
  return false;
}

function validateEmail(email) {
  var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
  return re.test(email);
}

// VARS
var offline = true;
var havePinCode = true;

// ONLINE/OFFLINE NOTIFICATION
$('body').prepend('<div id="offline-notification">Your device is...