Collaboration Store, Part III

“It is not enough to do your best: you must know what to do, and then do your best.”
W. Edwards Deming

Today we will build the widget for the initial set-up process for the Collaboration Store app. I always like to start with the visual portion and lay things out on the screen the way that I want to see them, but before we get into that, I should explain a little bit about my basic concept for the set-up process. There are actually three independent screens involved: 1) the initial screen where you enter all of the data about your installation, 2) an email verification screen where you enter a code that was sent to your email address to verify your access to the email account, and 3) a final completion screen that lets you know that you are all set up. The HTML for the widget will include all three screens, and I will use ng-show attributes to control which section is visible at any given stage of the process. Within the widget, I will refer to that as the phase, and set up a variable called c.data.phase to track the progress through the screens.

Here is what the initial data entry screen looks like:

Initial set-up data entry screen

… and here is the HTML for that initial (phase 1) screen:

<div class="row" ng-show="c.data.phase == 1">
  <div style="text-align: center;">
    <h3>${Collaboration Store Set-up}</h3>
  </div>
  <div>
    <p>
      Welcome to the Collaboration Store set-up process.
      There are two ways that you can set up the Collaboration Store on your instance:
      1) you can be the Host Instance to which all other instances connect, or
      2) you can connect to an existing Collaboration Store with their permission.
      To become the Host Instance of your own Collaboration Store, select <em>This instance will be
      the Host of the store</em> from the Installation Type choices below.
      If you are not the Host Instance, then you will need to provide the Instance ID of the
      Collaboration Store to which you would like to connect.
    </p>
  </div>
  <form id="form1" name="form1" novalidate>
    <div class="row">
      <div class="col-xs-12 col-sm-6">
        <snh-form-field
          snh-model="c.data.instance_type"
          snh-name="instance_type"
          snh-label="Installation Type"
          snh-type="select"
          snh-required="true"
          snh-choices='[{"value":"host", "label":"This instance will be the Host of the store"},
                        {"value":"client", "label":"This instance will connect to an existing store"}]'/>
      </div>
      <div class="col-xs-12 col-sm-6">
        <snh-form-field
          snh-model="c.data.host_instance_id"
          snh-name="host_instance_id"
          snh-label="Host Instance ID"
          snh-required="c.data.instance_type == 'client'"
          ng-show="c.data.instance_type == 'client'"/>
        <snh-form-field
          snh-model="c.data.store_name"
          snh-name="store_name"
          snh-label="Store Name"
          snh-required="c.data.instance_type == 'host'"
          ng-show="c.data.instance_type == 'host'"/>
      </div>
    </div>
    <div class="row">
      <div class="col-xs-12 col-sm-6">
        <snh-form-field
          snh-model="c.data.instance_name"
          snh-name="instance_name"
          snh-label="Instance Display Name"
          snh-required="true"/>
      </div>
      <div class="col-xs-12 col-sm-6">
        <snh-form-field
          snh-model="c.data.email"
          snh-name="email"
          snh-label="Email"
          snh-type="email"
          snh-required="true"/>
      </div>
    </div>
    <div class="row">
      <div class="col-sm-12">
        <snh-form-field
          snh-model="c.data.description"
          snh-name="description"
          snh-label="Instance Description"
          snh-type="textarea"
          snh-required="true"/>
      </div>
    </div>
  </form>
  <div class="row">
    <div class="col-sm-12" style="text-align: center;">
      <button class="btn btn-primary" ng-disabled="!(form1.$valid)" ng-show="c.data.instance_type == 'host'" ng-click="save();">${Create New Collaboration Store}</button>
      <button class="btn btn-primary" ng-disabled="!(form1.$valid)" ng-show="c.data.instance_type == 'client'" ng-click="save();">${Complete Set-up and Request Access}</button>
    </div>
  </div>
</div>

Basically, this is just a standard HTML form full of snh-form-fields organized into rows and columns. There are a couple of fields and a couple of buttons that are controlled by the value of that first SELECT, but other than that, it is pretty standard stuff, and there is no reason to get into any of that here.

The screen for the 2nd phase is much simpler, with only a single data entry field used to collect the code that was sent out in a Notification (more on that later) to verify the email address.

Email verification data entry screen

… and here is the HTML for the phase 2 screen:

<div class="row" ng-show="c.data.phase == 2">
  <div style="text-align: center;">
    <h3>${Email Verification}</h3>
  </div>
  <div>
    <p>
      A verification email has been sent to {{c.data.email}} with a one-time security code.
      Please enter the code below to continue.
    </p>
    <p>
      Cancelling this process will terminate the set-up process.
    </p>
  </div>
  <form id="form2" name="form2" novalidate>
    <div class="row">
      <div class="col-sm-12">
        <snh-form-field
          snh-model="c.data.security_code"
          snh-name="security_code"
          snh-label="Security Code"
          snh-required="true"
          placeholder="Enter the security code sent to you via email"/>
      </div>
    </div>
  </form>
  <div class="row">
    <div class="col-sm-12" style="text-align: center;">
      <button class="btn btn-default" ng-disabled="!(form2.$valid)" ng-click="cancel();">${Cancel}</button>
      <button class="btn btn-primary" ng-disabled="!(form2.$valid)" ng-click="verify();">${Submit Verification Code}</button>
    </div>
  </div>
</div>

The screen for the 3rd phase is even simpler, with no data entry fields at all. It is just a message indicating that set-up is complete and was successful.

Set-up completion screen

… and here is the HTML for the phase 3 screen:

<div class="row" ng-show="c.data.phase == 3">
  <div style="text-align: center;">
    <h3>${Set Up Complete!}</h3>
  </div>
  <div>
    <p>${Congratulations!}</p>
    <p>
      The Collaboration Store set-up is now complete. Your instance has been successfully registered with the
      <b class="text-primary">{{c.data.registeredHostName}}</b> ({{c.data.registeredHost}})
      Host and is now ready to utilize the Collaboration Store features.
    </p>
  </div>
</div>

That pretty much takes care of the visual portion of the widget, which is usually the easiest part. Now we have to put all of the code underneath to make everything do all of the things that we want to do during the set-up process. One of the first things that we will want to do is to make sure that the set-up process has not already been completed. We should be able to tell that right off the bat by looking to see if there is a record in the table for the instance. If there is, then things have already been set up, and so we can artificially advance things to phase 3 and put up that final screen in the event that someone tries to go through the process a second time.

Assuming that this is the first time through, though, we will want to validate the data, and assuming that all goes well, we will want to send out the notification with the random code and advance the phase so that we can verify the email address. Once that’s done, we will need to update the database, and in the case of a client instance, we will need to register the instance with the host. To make all of that work, we will need some REST services, and probably a Script Include to contain some code to handle both sides of those inter-instance communications. We are definitely not going to get through all of that in a single installment, but we can take them all on, one issue at a time, as we work our way through all of the parts and pieces that will need to be built. Probably the easiest thing to tackle next would be the client-side code of the widget, so let’s start with that next time out.