Tuesday, October 21, 2014

Employee Time Log using Bootstrap, AngularJS and WCF Service

Hi Guys,

This time I made Employee Time Logging application for an organisation using Bootstrap, AngularJS and WCF Services.  This is a simple application which consumes (GET,POST) JSON enabled WCF Services using Angular JS. Hope you like it.

I used a login screen to allow the employees to login directly using there Domain Username and Password. Then I used localStorage module to store the user account info.

Login Page.

Page is made to work in both mobile and pc browsers using bootstrap.














My Time Logs Page

User can view all of his time logs.













Modal to Add New Log
















Before you Start,

1) Any version of Visual Studio

Step One : The Solution

First create a Web Application as following.


Step Two : Code and Styles

Since this is a Website I will not include all the code here. I will include only the AngularJS code.

1) Open js -> app.js and paste the following code

var appmodule = angular.module('EmployeeApp', ['ngRoute', 'ngAnimate', 'smart-table', 'LocalStorageModule', 'angular-loading-bar',
'ui.bootstrap.datetimepicker']);
appmodule.controller('IndexController', ["$scope", "$location", "authService", IndexController]);
appmodule.controller('LoginController', ["$scope", "$location", "authService", LoginController]);
appmodule.controller('TimeLogController', ["$scope", "$http", "authService","$filter", TimeLogController])
    .directive('newTimeLog', function () {
        return {
            templateUrl: 'Views/Partials/new-time-log.html'
        };
    });

appmodule.run(['authService', function (authService) {
    authService.fillAuthData();
}]);

appmodule.config(['$routeProvider', '$locationProvider',
    function ($routeProvider, $locationProvider) {
        $routeProvider
          
         .when('/myTimeLogs', {
             templateUrl: 'Views/Partials/MyTimeLogs.html',
             controller: 'IndexController',
             controllerAs: 'index'
         })
        .when('/login', {
            templateUrl: 'Views/Partials/Login.html',
            controller: 'LoginController',
            controllerAs: 'login'
        })
        

        .otherwise({
            redirectTo: '/login'
          });;

        $locationProvider.html5Mode(true);
    }]);


function IndexController($scope, $location, authService) {
    var scope = $scope;


    scope.logOut = function () {
        authService.logOut();
        $location.path('/login');
    }

    scope.authentication = authService.authentication;
    
}

function LoginController($scope, $location, authService) {
    var scope = $scope;
    scope.message = '';

    scope.login = function (loginData) {

        authService.login(loginData).then(function (response) {


            if (JSON.parse(response)) {
                $location.path('/myTimeLogs');
            }
            else {
                scope.message = 'Login UnSuccessful';
            }

        },
         function (err) {
             scope.message = err;
         });

    }

    scope.authentication = authService.authentication;

     
}

function TimeLogController($scope, $http, authService, $filter) {
    var scope = $scope;
    
    scope.collection = [];
    scope.message = '';
    scope.alertClass = 'alert-danger';
    
    scope.rowCollection = [];
    scope.CurrentLog = [];

    scope.StartTime = '';
    scope.EndTime = '';
   
    scope.authentication = authService.authentication;

    scope.SaveLog = function (log) {
        log.StartTime = getWCFJsonDate(log.StartTime);
        log.EndTime = getWCFJsonDate(log.EndTime);
        log.CreatedBy = scope.authentication.userName;

        
        $http.post('/Services/EmployeeService.svc/SaveLog', log).success(function (response) {


            if (JSON.parse(response)) {
                getAllMyTimeLogs(scope, $http, scope.authentication.userName);
                //scope.Reset();
                scope.alertClass = 'alert-success';
                scope.message = 'Saved Successfully!';
            }


        }).error(function (err, status) {
            scope.message = err;
        });
    }

    scope.Reset = function () {
    

        var responsePromise = $http.get("/Services/EmployeeService.svc/GetLogById?id=2");

        responsePromise.success(function (data, status, headers, config) {
            scope.CurrentLog = clone(data[0]);
            scope.message = '';
            scope.StartTime = '';
            scope.EndTime = '';
            scope.CurrentLog.Duration = 0;
            scope.alertClass = 'alert-danger';

        });
        responsePromise.error(function (data, status, headers, config) {
            scope.alertClass = 'alert-danger';
            scope.message = data;
            
        });

    }
    
    scope.GetTotal = function (log) {


        var total = 0.0;

        for (var i = 0; i < scope.collection.length; i++) {

            console.log(getDate(log["CreatedOn"]).toDateString() + '==' +
                getDate(scope.collection[i]["CreatedOn"]).toDateString());

            if (getDate(scope.collection[i]["CreatedOn"]).toDateString() ==
                getDate(log["CreatedOn"]).toDateString()) {


                total = total + parseFloat(scope.collection[i]["Duration"]);

            }
        }


        return "width:" + parseInt((parseFloat(log["Duration"]) / total) * 100) +"%";

     }

    scope.Reset();
    scope.Refresh = function () {
        getAllMyTimeLogs(scope, $http, scope.authentication.userName);
    }
      
    scope.Refresh();
        
       
}

function getAllMyTimeLogs(thisscope, http, userName) {
    var responsePromise = http.get("/Services/EmployeeService.svc/GetAllMyTimeLogs?userName=" + userName);

    responsePromise.success(function (data, status, headers, config) {

        thisscope.rowCollection = data;
        thisscope.collection = data;
        thisscope.displayedCollection = [].concat(thisscope.rowCollection);
        thisscope.itemsByPage = 10;

    });
    responsePromise.error(function (data, status, headers, config) {
        alert("AJAX failed!");
    });
}


function clone(obj) {
    if (obj == null || typeof (obj) != 'object')
        return obj;

    var temp = obj.constructor(); // changed

   
    
    return temp;
}

function getWCFJsonDate(date)
{
    return '/Date(' + new Date(date).getTime() + '+0300)/';
}

function getDate(dateTo)
{
    var dt = new Date();
    dt.setTime(dateTo.substring(6, dateTo.indexOf('+')));

     return dt;

    
}

2) Open js -> authService.js and paste the following code

'use strict';
var app = angular.module('EmployeeApp');
app.factory('authService', ['$http', '$q', 'localStorageService', function ($http, $q, localStorageService) {

    var serviceBase = '/Services/EmployeeService.svc/';
    var authServiceFactory = {};

    var _authentication = {
        isAuth: false,
        userName: ""
    };
      

    

    var _login = function (loginData) {

        var success = false;

       

        var deferred = $q.defer();

        $http.post(serviceBase + 'Login', loginData).success(function (response) {

            
            if (JSON.parse(response)) {
                localStorageService.set('authorizationData', { userName: loginData.userName });

                _authentication.isAuth = true;
                _authentication.userName = loginData.userName;
            }
            
            
            deferred.resolve(response);
            

        }).error(function (err, status) {
            _logOut();
            deferred.reject(err);
        });

        return deferred.promise;

    };

    var _logOut = function () {

        localStorageService.remove('authorizationData');

        _authentication.isAuth = false;
        _authentication.userName = "";
        

    };

    var _fillAuthData = function () {
       
        var authData = localStorageService.get('authorizationData');
        if (authData) {
            _authentication.isAuth = true;
            _authentication.userName = authData.userName;
            
        }

    };

   

    
    authServiceFactory.login = _login;
    authServiceFactory.logOut = _logOut;
    authServiceFactory.fillAuthData = _fillAuthData;
    authServiceFactory.authentication = _authentication;
   


    return authServiceFactory;

}]);

3) Open the EmployeeService,svc,cs and paste this code

using System;
using System.Collections.Generic;
using System.DirectoryServices.AccountManagement;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace EmployeeTimeLog.Services
{
    [Serializable]
    [DataContract]
    public class LoginData
    {
        [DataMember]
        public string userName { get; set; }
        [DataMember]
        public string password { get; set; }
    }


    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "EmployeeService" in code, svc and config file together.
    // NOTE: In order to launch WCF Test Client for testing this service, please select EmployeeService.svc or EmployeeService.svc.cs at the Solution Explorer and start debugging.
    public class EmployeeService : IEmployeeService
    {
        [OperationBehavior]
        public bool Login(LoginData login)
        {
            bool valid = true;
            using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
            {
                valid = context.ValidateCredentials(login.userName, login.password);
            }

            return valid;
        }

        [OperationBehavior]
        public List<EP_TimeLog> GetAllMyTimeLogs(string userName)
        {
            using (EmployeePortalDataContext context = new EmployeePortalDataContext())
            {
                var temp = (from r in context.EP_TimeLogs
                            where r.CreatedBy.Trim().ToLower() == userName.Trim().ToLower()
                            select r);
                return temp.ToList();

            }
        }

        [OperationBehavior]
        public List<EP_TimeLog> GetLogById(long id)
        {
            using (EmployeePortalDataContext context = new EmployeePortalDataContext())
            {
                var temp = (from r in context.EP_TimeLogs where r.ID == id select r);
                return temp.ToList();
            }
        }

        [OperationBehavior]
        public bool SaveLog(EP_TimeLog log)
        {
            bool valid = false;
            using (EmployeePortalDataContext context = new EmployeePortalDataContext())
            {
                
                
                log.EditedBy = log.CreatedBy;
                log.EditedOn = log.CreatedOn = DateTime.Now;

                context.EP_TimeLogs.InsertOnSubmit(log);
                context.SubmitChanges();
                valid = true;
            }

            return valid;
        }
    }

}

4) Open the IEmployeeService,cs and paste this code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace EmployeeTimeLog.Services
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IEmployeeService" in both code and config file together.
    [ServiceContract]
    public interface IEmployeeService
    {
        [OperationContract]
        [WebInvoke(UriTemplate = "/Login",
            RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json, Method = "POST")]
        bool Login(LoginData login);

        [OperationContract]
        [WebGet(UriTemplate = "/GetAllMyTimeLogs?userName={userName}",
        ResponseFormat = WebMessageFormat.Json)]
        List<EP_TimeLog> GetAllMyTimeLogs(string userName);

        [OperationContract]
        [WebInvoke(UriTemplate = "/SaveLog",
            RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json, Method = "POST")]
        bool SaveLog(EP_TimeLog log);

        [OperationContract]
        [WebGet(UriTemplate = "/GetLogById?id={id}",
            ResponseFormat = WebMessageFormat.Json)]
        List<EP_TimeLog> GetLogById(long id);
        
    }
}

5) Open Views -> Partials -> Login.html and paste following


    <form role="form" ng-controller="LoginController">

          <div class="panel panel-primary">
           <div class="panel-heading">
               <img src="../../Images/logo.png" /></div>
              <div class="panel-body">
                  <input type="text" class="form-control" placeholder="Username" data-ng-model="loginData.userName" required autofocus>
            <input type="password" class="form-control" placeholder="Password" data-ng-model="loginData.password" required>
            
            <button class="btn btn-primary" type="submit" data-ng-click="login(loginData)">Login</button>
              <div data-ng-hide="message == ''" class="alert alert-danger">
                {{message}}
            </div>

              </div>
              </div>


   
</form>

6) Open Views -> Partials -> MyTimeLogs.html and paste following


<div class="container" ng-controller="TimeLogController">

    


    
    <div class="panel panel-primary">
           <div class="panel-heading">
             <h1 >My Time Logs</h1>   
       
            </div>
    <div class="panel-body">
              <div class="pull-right"><a data-toggle="modal" data-target="#myModal" ng-click="Reset()" class="btn btn-primary"><span class="glyphicon glyphicon-plus"></span>  Add</a>
                  <a  class="btn btn-success" ng-click="Refresh()"><span class="glyphicon glyphicon-refresh"></span>  Refresh</a>

              </div> 
                   <div class="table-responsive">
                       <table class="table table-striped table-hover" st-table="displayedCollection" st-safe-src="rowCollection" width="100%"  >
<thead>
            <tr>

<th colspan="7">
                
              <div class="input-group pull-right" style="max-width:470px;">
                <input st-search="" placeholder="Search" class="input-sm form-control" type="search">
                  
                
              </div>
         



                
</th>
                
</tr>
<tr>
            <th>
                    Name
                </th>
                <th>
                    Description
                </th>
                <th>
                    Start Time
                </th>
                 <th>
                    End Time
                </th>
                <th>
                    Duration (Mins)
                </th>
            <th>
                Percentage 
            </th>
                
</tr>

</thead>
<tbody>
<tr ng-repeat="log in displayedCollection | orderBy:CreatedOn:true">

            <td>{{ log.Name }}</td>
             <td>{{ log.Description }}</td>
             
            <td>{{ log.StartTime.substring(6, log.StartTime.indexOf('+')) | date:'EEEE, dd MMM yyyy HH:mm:ss ' }}</td>
            <td>{{ log.EndTime.substring(6,  log.EndTime.indexOf('+')) | date:'EEEE, dd MMM yyyy HH:mm:ss ' }}</td>
            <td>{{ log.Duration }}</td>



           <td>
               <div class="progress progress-striped" style="width:80px" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="Total Percentage of work for the day!" >
  <div class="progress-bar progress-bar-success" style="{{ GetTotal(log) }}"></div>
</div>
                </td>

               
                             
          
                        
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="7" >
<div st-pagination="" class="pull-right" st-items-by-page="itemsByPage" st-displayed-pages="7"></div>
</td>
</tr>
</tfoot>
</table>
                   </div>
            
             
            </div>
         </div>

    

<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
        <h4 class="modal-title" id="myModalLabel">New Time Log</h4>
      </div>
      <div class="modal-body">
        <div ng-controller="TimeLogController">
  <div new-time-log></div>
</div>
      </div>
     
    </div>
  </div>
</div>

          
    </div>

7) Open Views -> Partials -> new-time-log.html and paste following


 <form name="LogForm" ng-submit="LogForm.$valid && SaveLog(CurrentLog)"   novalidate>
    


                            
<div >
                        <div class="panel panel-primary">
                           
                            <div class="panel-body">
                              

                           

                            <div  class="form-group">
                                <label>Name </label>
                                <input type="text" class="form-control" rows="3"  ng-model="CurrentLog.Name" maxlength="250" required></input>
                            </div>

                                 <div  class="form-group">
                                <label>Description</label>
                                     <textarea class="form-control" ng-model="CurrentLog.Description" maxlength="2000" required> </textarea>
                                
                            </div>

                            
                                <div  class="form-group">
                                <label>Start Time</label>
                                     <span> {{ CurrentLog.StartTime = (StartTime | date:'yyyy-MM-dd HH:mm:ss')}}</span>
                                   <div class="dropdown">
    <a  class="dropdown-toggle" id="dropdown1" role="button" data-toggle="dropdown" data-target="#" href="#">Click here to Set Start Time</a>
    <ul class="dropdown-menu" role="menu">
        <datetimepicker data-ng-model="StartTime" data-datetimepicker-config="{ dropdownSelector: '#dropdown1' }"/>
    </ul>
</div>
    </div>

                                <div  class="form-group">
                                <label>End Time</label>
                                     <span> {{ CurrentLog.EndTime = (EndTime | date:'yyyy-MM-dd HH:mm:ss')}}</span>
                                   <div class="dropdown">
    <a  class="dropdown-toggle" id="dropdown2" role="button" data-toggle="dropdown" data-target="#" href="#">Click here to Set Start Time</a>
    <ul class="dropdown-menu" role="menu">
        <datetimepicker data-ng-model="EndTime" data-datetimepicker-config="{ dropdownSelector: '#dropdown2' }"/>
    </ul>
</div>
    </div>
                               
                           <div>
                                 <div data-ng-hide="CurrentLog.Duration > 0" class="alert alert-danger">
                <strong>Invalid</strong> Start Time and End Time are invalid!
            </div>

                            </div>

                               

                                 <div  class="form-group">
                                <label>Duration</label><br />
                                     <span>
                                 {{ CurrentLog.Duration = (EndTime - StartTime)/60000 }} Min(s)
                                         </span>
                            </div>

                                 <div data-ng-hide="message == ''" class="alert " ng-class="alertClass">
                {{message}}
            </div>


                                <div class="pull-right">
               
               
            <button type="submit" class="btn btn-primary"  ><span class="glyphicon glyphicon-floppy-disk"></span> Save</button>
               
               
                            <button type="reset" class="btn btn-primary" ng-click="Reset()"  ><span class="glyphicon glyphicon-remove"></span> Reset</button>
               </div>

                        </div>
                       
                    </div>
                                
                

            
        
          </form>
 
8) Open Views -> Partials -> index.html and paste following

<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<title>Employee Time Log</title>
<meta name="generator" content="Bootply" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link href="css/bootstrap.min.css" rel="stylesheet">
        <link rel="icon" 
      type="image/png"  href="Images/favicon.png" />
        <script src="js/angular.min.js"></script>
    <script src="js/angular-route.js"></script>
    <script src="js/angular-local-storage.min.js"></script>
    <link href="css/loading-bar.css" rel="stylesheet" />
    <script src="js/loading-bar.js"></script>
    <script src="js/angular-animate.js"></script>
    <script src="js/moment.js"></script>
        <script src="js/datetimepicker.js"></script>
    <script src="js/app.js"></script>
    
    <link href="css/datetimepicker.css" rel="stylesheet" />
        <script src="js/authService.js"></script>
    <script src="js/smart-table.min.js"></script>
<!--[if lt IE 9]>
<script src="//html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link href="css/styles.css" rel="stylesheet">
    <link href="css/loading-bar.css" rel="stylesheet" />
</head>
<body ng-app="EmployeeApp" >
<div class="navbar navbar-inverse" ng-controller="IndexController">
                <div class="navbar-header">
                  <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-inverse-collapse">
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                  </button>
                  <a class="navbar-brand" href="#">Employee Time Log</a>
                </div>
                <div class="navbar-collapse collapse navbar-inverse-collapse">
                  
                  <ul class="nav navbar-nav navbar-right">
                   
                    <li data-ng-hide="!authentication.isAuth"><a  href="/myTimeLogs"><span class="glyphicon glyphicon-th-list"></span>  My Time Logs</a></li>
                    <li data-ng-hide="!authentication.isAuth" class="dropdown">
                      <a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="glyphicon glyphicon-user"></span> Welcome {{authentication.userName}} <b class="caret"></b></a>
                      <ul class="dropdown-menu">
                        <li><a ng-click="logOut()"><span class="glyphicon glyphicon-off"></span> Log out</a></li>
                        
                      </ul>
                    </li>
                  </ul>
                </div>
              </div>


<!--main-->
<div class="container" id="main">
    
  <div class="view-animate-container">
    <div ng-view class="view-animate"></div>
  </div>
    </div>
   
        
<!-- script references -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<script src="js/bootstrap.min.js"></script>

</body>

</html>