Donation UI

Using the latest Semantic UI, introduce a simple but well structured User Interface into the donation-service-play application.

Semantic UI

SInstead do downloading and incorporating the Semantic UI libraries into our application - as we have donw heretofore - it may be more effective to load the semantic assets from a content delivery network. This one is popular:

and it hosts the semantic libraries:

These is the latest version we need:

//cdnjs.cloudflare.com/ajax/libs/semantic-ui/1.0.1/semantic.min.css
//cdnjs.cloudflare.com/ajax/libs/semantic-ui/1.0.1/semantic.min.js

In the donation-service-play app, these links will need to be introduced into main.html (note we are including jquery as well, which must appear before the semantic includes):

app/views/main.html

  <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js" type="text/javascript" charset="${_response_encoding}"></script>
  <link rel="stylesheet" media="screen"  href="//cdnjs.cloudflare.com/ajax/libs/semantic-ui/1.0.1/semantic.min.css">
  <script src="//cdnjs.cloudflare.com/ajax/libs/semantic-ui/1.0.1/semantic.min.js" type="text/javascript" charset="${_response_encoding}"></script>

Semantic UI need some javascript to initialise the controls you may uses. We will need radio buttons, dropdown and a progress bar. This fragment can be included at the end of the main.html file:

     <script>
       $(document).ready(function()
       {
         $('.ui.radio.checkbox').checkbox();  
         $('.ui.dropdown').dropdown({on: 'hover' });
         $('.progress').progress();
       });
     </script> 

We will also introduce a footer:

views/footer.html

<div class="ui divider"></div>

<footer class="ui divided horizontal footer link list">
  <div class="item">Donation Studios 2013</div>
  <div class="item">
    Built using  <a href="http://www.semantic-ui.com" target="_blank">Semantic ui</a>
  </div>
  <div class="item">
    and the  <a href="http://www.playframework.com" target="_blank">Play Framework</a>
  </div>
</footer>

Finally, the complete main.html

<!DOCTYPE html>
<html>
    <head>
        <title>#{get 'title' /}</title>
        <meta charset="${_response_encoding}">
        <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js" type="text/javascript" charset="${_response_encoding}"></script>
        <link rel="stylesheet" media="screen"  href="//cdnjs.cloudflare.com/ajax/libs/semantic-ui/1.0.1/semantic.min.css">
        <script src="//cdnjs.cloudflare.com/ajax/libs/semantic-ui/1.0.1/semantic.min.js" type="text/javascript" charset="${_response_encoding}"></script>
        <link rel="stylesheet" media="screen" href="@{'/public/stylesheets/main.css'}">
        #{get 'moreStyles' /}
        <link rel="shortcut icon" type="image/png" href="@{'/public/images/favicon.png'}">
        #{get 'moreScripts' /}
    </head>
    <body>
        #{doLayout /}
        #{include "footer.html" /}

     <script>
       $(document).ready(function()
       {
         $('.ui.radio.checkbox').checkbox();  
         $('.ui.dropdown').dropdown({on: 'hover' });
         $('.progress').progress();
       });
     </script> 

    </body>
</html>

Routes

We already have out REST routes in place. These are additional routes to service the UI:

# Home page
GET      /                                   Accounts.index

# Accounts page
GET    /signup                               Accounts.signup
GET    /login                                Accounts.login
GET    /logout                               Accounts.logout
POST   /authenticate                         Accounts.authenticate
POST   /register                             Accounts.register

# Donation page
GET    /donation                             DonationController.index
POST   /donation/donate                      DonationController.donate
GET    /donation/report                      DonationController.renderReport

We will need some convenience methods in the User model class:

User

  public static User findByEmail(String email)
  {
    return find("email", email).first();
  }  

  public boolean checkPassword(String password)
  {
    return this.password.equals(password);
  } 

Imagery

Our UI will make use of some imagery - these images should be saved to the public/images folder:

![](img/homer.png)
![](img/homer2.png)
![](img/homer3.png)
![](img/homer4.jpeg)
![](img/homer5.jpg)

Controllers

We have controllers to service the API. These two controllers will service the conventional web UI:

DonationController

package controllers;

import play.*;
import play.mvc.*;
import java.util.*;
import models.*;

public class DonationController extends Controller
{
  public static void index()
  {
    User user = Accounts.getCurrentUser();
    String prog = getPercentTargetAchieved();
    String progress = prog;
    Logger.info("Donation ctrler : user is " + user.email);
    Logger.info("Donation ctrler : percent target achieved " + progress);
    List<Donation> donations = user.donations;
    render(user, progress, donations);
  }

  public static void donate(int amountDonated, String methodDonated)
  {
    User user = Accounts.getCurrentUser();
    Logger.info("amount donated " + amountDonated + " " + "method donated " + methodDonated);
    Donation donation = new Donation(amountDonated, methodDonated);
    user.donations.add(donation);
    user.save();
    index();
  }

  private static long getDonationTarget()
  {
    return 20000;
  }

  public static String getPercentTargetAchieved()
  {
    List<Donation> allDonations = Donation.findAll();
    long total = 0;
    for (Donation donation : allDonations)
    {
      total += donation.amount;
    }
    long target = getDonationTarget();
    long percentachieved = (total * 100 / target);
    String progress = String.valueOf(percentachieved);
    Logger.info("Percent of target achieved (string) " + progress + " percentachieved (long)= " + percentachieved);
    return progress;
  }

  public static void renderReport()
  {
    User user = Accounts.getCurrentUser();
    List<Donation> donations = user.donations;
    render(donations);
  }
}

Accounts

package controllers;

import play.*;
import play.mvc.*;
import models.*;

public class Accounts extends Controller
{
  public static void index()
  {
    render();
  }

  public static void signup()
  {
    render();
  }

  public static void register(boolean usCitizen, String firstName, String lastName, String email, String password)
  {
    Logger.info( firstName + " " + lastName + " " + email + " " + password);
    User user = new User(firstName, lastName, email, password);
    user.save();
    index();
  }

  public static void login()
  {
    render();
  }

  public static void logout()
  {
    session.clear();
    index();
  }

  public static void authenticate(String email, String password)
  {
    Logger.info("Attempting to authenticate with " + email + ":" + password);

    User user = User.findByEmail(email);
    if ((user != null) && (user.checkPassword(password) == true))
    {
      Logger.info("Successfull authentication of  " + user.firstName + " " + user.lastName);
      session.put("logged_in_userid", user.id);
      DonationController.index();
    }
    else
    {
      Logger.info("Authentication failed");
      login();
    }
  }

  public static User getCurrentUser()
  {
    String userId = session.get("logged_in_userid");
    if (userId == null)
    {
      index();
    }
    User logged_in_user = User.findById(Long.parseLong(userId));
    Logger.info("In Accounts controller: Logged in user is " + logged_in_user.firstName);
    return logged_in_user;
  }
}

Account Segment Views

We will break up the UI into more fine grained components. In the App/views folder, create a new folder called 'segments' and introduce these files:

views/segments/welcome.html

<section class="ui stacked segment">
  <div class="ui grid">
    <aside class="six wide column">
      <img src="/public/images/homer.png" class="ui medium image">
    </aside>
    <article class="ten wide column">
      <header class="ui  header"> Help Me Run Springfield  </header>
      <p> Donate what you can now - No Bitcoins accepted! </p>
    </article>
  </div>
</section>

views/segments/signup.html

<section class="ui raised segment">
  <div class="ui grid">
    <div class="ui ten wide column">
      <div class="ui stacked fluid form segment">
          <form action="/register" method="POST">
            <h3 class="ui header">Register</h3>
            <div class="two fields">
              <div class="field">
                <label>First Name</label>
                <input placeholder="First Name" type="text" name="firstName">
              </div>
              <div class="field">
                <label>Last Name</label>
                <input placeholder="Last Name" type="text" name="lastName">
              </div>
            </div>
            <div class="field">
              <label>Email</label>
              <input placeholder="Email" type="text" name="email">
            </div>
            <div class="field">
              <label>Password</label>
              <input type="password" name="password">
            </div>
            <button class="ui blue submit button">Submit</button>
          </form>
        </div>  
      </div>
      <aside class="ui five wide column">
        <img src="/public/images/homer3.png" class="ui medium image">
      </aside>
    </div>  
</section>

views/segments/login.html

 <section class="ui raised segment">
   <div class="ui grid">
     <aside class="ui six wide column">
       <img src="/public/images/homer2.png" class="ui medium image">
     </aside>
     <div class="ui ten wide column fluid form">
       <div class="ui stacked segment">
         <form action="/authenticate" method="POST">
           <h3 class="ui header">Log-in</h3>
           <div class="field">
             <label>Email</label>
             <input placeholder="Email" type="text" name="email">
           </div>
           <div class="field">
             <label>Password</label>
             <input type="password" name="password">
           </div>
           <button class="ui blue submit button">Login</button>
         </form>
       </div>
     </div>
   </div>
</section>

views/segments/welcomemenu.html

  <nav class="ui inverted menu">
    <header class="header item"> <a href="/"> Donation </a> </header>
    <div class="right menu">
      <a class="item" href="/signup"> Signup</a>
      <a class="item" href="/login">  Login</a>
    </div>
  </nav>    

These are all Html 5 semantic elements that we will build the Accounts UX from.

Donation Segment Views

Here are Html5 semantic elements to service the Donation Controller's views:

Views/segments/donate.html

<section class="ui raised segment">
  <div class="ui grid ">
    <div class="ui form six wide column">
      <div class="ui stacked segment">
        <form action="/donation/donate" method="POST">
          <div class="ui dropdown" name="amount">
            <input type="hidden" name="amountDonated">
            <div class="text">Select Amount</div>
            <i class="dropdown icon"></i>
            <div class="menu">
              <div class="item">50</div>
              <div class="item">100</div>
              <div class="item">1000</div>
            </div>
          </div>
          <div class="grouped inline fields">
            <div class="field">
              <div class="ui radio checkbox">
                <input type="radio" name="methodDonated" value="paypal">
                <label>Paypal</label>
              </div>
            </div>
            <div class="field">
              <div class="ui radio checkbox">
                <input type="radio" name="methodDonated" value="direct">
                <label>Direct</label>
              </div>
            </div>
          </div>
          <button class="ui blue submit button"> Donate </button>
        </form>
      </div>
    </div>
    <aside class="six wide column">
      <img src="/public/images/homer4.jpeg" class="ui medium image">
    </aside>    
  </div>

Views/segments/report.html

  <section class="ui raised segment">
    <div class="ui grid">
    <aside class="six wide column">
      <img src="/public/images/homer5.jpg" class="ui medium image">
    </aside>
    <article class="eight wide column">
      <table class="ui celled table segment">
        <thead>
          <tr>
            <th>Amount</th>
            <th>Method donated</th>
          </tr>
        </thead>
        <tbody>
          #{list items:donations, as:'donation'}
            <tr>
              <td>${donation.amount}</td>
              <td>${donation.method}</td>
            </tr>
          #{/list}
        </tbody>
      </table>
    </article>
  </div>
</section>

Accounts Views

With the segment building blocks in place, we can switch our attention to the Controllers - and the views they will be rendering.

Here are the templates for views/Accounts:

views/Accounts/index.html

#{extends 'main.html' /} 
#{set title:'Donations' /} 

#{include "segments/welcomemenu.html" /}
#{include "segments/welcome.html" /}

views/Accounts/login.html

#{extends 'main.html' /}
#{set title:'Login to Donation' /}

#{include "segments/welcomemenu.html" /}
#{include "segments/login.html" /} 

views/Accounts/signup.html

#{extends 'main.html' /}
#{set title:'Signup for Donation' /}

#{include "segments/welcomemenu.html" /}
#{include "segments/signup.html" /} 

Note that these view load the appropriate segments.

You should be able to power up the play app now and test our the three Accounts screens:

DonationController Views

And the final pieces - the templates for views/DonationController:

views/DonationController/index.html

#{extends 'main.html' /}
#{set title:'Donation Request' /} 

<nav class="ui inverted menu">
  <header class="header item"> <a href="/"> Donation </a> </header>
  <div class="right menu">
    <a class="active item" href="/donation"> Donate</a>
    <a class="item" href="/donation/report">  Report</a>
    <a class="item" href="/logout">  Logout</a>
  </div>
</nav>    

<section class="ui raised segment">

  #{include "Segments/donate.html" /} 

  <div class="ui  divider"></div>

  <div class="ui teal progress"  data-percent="${progress}" id="mainprogress">
    <div class="bar"> </div>
  </div>  

</section>

views/DonationController/renderReport.html

#{extends 'main.html' /} 
#{set title:'Report' /} 

<nav class="ui inverted menu">
  <header class="header item"> <a href="/"> Donation </a> </header>
  <div class="right menu">
    <a class="item" href="/donation"> Donate</a>
    <a class="active item" href="/donation/report">  Report</a>
    <a class="item" href="/logout">  Logout</a>
  </div>
</nav>    

#{include "Segments/report.html" /} 

Again, note how we are including the segments we need.

The app should run now as expected. Make sure the progress bar behaves correctly.

Exercises

Archive of the completed project:

-dontion-service-play.zip

Exercise 1

The donation-service-play application can service the REST API and the Web UI simultaneously. Launch the app and also the donation-android-v6 from last week. See if you can inspect donations registered from the android app using the web ui and vice versa

Exercise 2

Deploy the application to the Heroku - and verify that the UI and the Android client operate as expected using Heroku

Exercise 3

This is a revised 'dashboard' style interface for the Donation play service:

It doesnt make much sense. However, as we have 'segmented' the UI, you should be able to build this UX by just introducing a single new view. (Hint - the html template is in the slides!)