Skip to content

Instantly share code, notes, and snippets.

@DanThiffault
Created December 11, 2013 08:41

Revisions

  1. DanThiffault created this gist Dec 11, 2013.
    33 changes: 33 additions & 0 deletions jsbin.ewoCogu.css
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,33 @@
    ::-webkit-inner-spin-button { display: none; }
    ::-webkit-datetime-edit {}

    .datePicker {
    position: relative;
    margin-bottom: 15px;
    }

    .ul.calendar-header {
    display: none;
    }

    @media (min-width:768px) {
    .ul.calendar-header {
    display: table;
    }

    .calendar-table ul.calendar-header > li {
    height: 1em;
    }

    .sidebar {
    min-height: 1000px;
    }
    }

    .apply-reimbursement {
    /*color: blue; */
    }

    .request .amount.rejected {
    background-color: #d9534f;
    }
    143 changes: 143 additions & 0 deletions jsbin.ewoCogu.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,143 @@
    <!DOCTYPE html>
    <html ng-app="expense">
    <head>
    <meta name="description" content="Work 365 Expense" />
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.3/angular.min.js"></script>
    <script src="https://s3-eu-west-1.amazonaws.com/iotap-demos/libraries/ui-bootstrap-tpls-0.7.0.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.1/underscore-min.js"></script>


    <link href="http://therandomtests.in/iotap/css/bootstrap.css" rel="stylesheet" type="text/css" />

    <meta charset=utf-8 />
    <title>Work 365 Expense</title>
    </head>
    <body ng-controller="CalendarController">
    <div class="wrapper container">
    <div class="sidebar">
    <div class="profile">
    <img style="width: 100%" src="{{currentUser.pictureUrl}}" />
    <span class="profile-name">{{currentUser.name}}</span>
    </div>
    <div class="leave-remaining">
    <small>Per Diem</small>
    <h3>&#8377; 2000</h3>
    <div class="double">
    <div>
    <small>{{unapprovedExpenses}} unapproved expenses</small>
    </div>
    </div>
    <div style="margin-top:15px">
    <a class="apply-reimbursement">
    <span class="glyphicon glyphicon-plus-sign" ng-click="toggleReimbursementForm()"></span>
    <span ng-click="toggleReimbursementForm()">Apply for reimbursement</span>
    </a>
    </div>
    </div>
    </div>

    <div class="content col-md-9">
    <div class="header">
    <input type="month" ng-model="monthString" class="pull-right datePicker"/>
    </div>
    <div class="table clearfix">
    <div class="calendar-table">
    <ul class="calendar-header">
    <li>Sunday</li>
    <li>Monday</li>
    <li>Tuesday</li>
    <li>Wednesday</li>
    <li>Thursday</li>
    <li>Friday</li>
    <li>Saturday</li>
    </ul>
    <ul ng-repeat="w in weeks">
    <li ng-repeat="d in w" ng-class="dateClass(d)" ng-click="selectDay($event,d)">
    <div class="date">{{d | date:'dd MMM'}}</div>
    <div class="request" ng-repeat="(status, expenses) in d.personal">
    <span class="amount" ng-class="expenseStatusCount(status,expenses)">{{expenses.length}}</span>
    <span class="type">{{status}}</span>
    </div>
    <div class="request" ng-repeat="(status, expenses) in d.staff">
    <span class="amount" ng-class="expenseStatusCount(status,expenses)">{{expenses.length}}</span>
    <span class="type">{{status}}</span>
    </div>
    </li>
    </ul>
    </div>
    </div>
    </div>
    </div>

    <div class="date-detail" ng-show="selectedDay">
    <!--
    <div class="date">
    <small>sat-wed</small>
    <h4>21-25 Dec</h4>
    <h3>Project deadline for <em>Eastbound &amp; Down</em></h3>
    </div>
    -->
    <div ng-repeat="(status, expenses) in selectedDay.personal">
    <div class="person" ng-repeat="expense in expenses">
    <div class="btn-group btn-group-sm">
    <button type="button" class="btn btn-default" ng-click="toggleCommentArea(expense)"><span class="glyphicon glyphicon-comment"></span></button>
    </div>
    <h4>{{employees[expense.user].name}} <small>{{status}}</small></h4>
    <h6>{{expense.title}}: &#8377; {{expense.amount}}</h6>
    <p ng-repeat="c in expense.comments"><q>{{c.comment}}</q> - {{c.name}}</p>
    <div ng-show="expense.showComment">
    <textarea ng-model="newComment.comment" placeholder="Enter your comment" style="width: 100%; margin-top: 10px; border: solid 1px #CCC; padding: 10px"></textarea><br/>
    <button ng-click="addNewComment(expense, newComment)" class="btn btn-primary" style="margin-top: 10px">Add Comment</button>
    </div>
    <hr/>
    </div>
    </div>
    <div ng-repeat="(status, expenses) in selectedDay.staff">
    <div class="person" ng-repeat="expense in expenses">
    <div class="btn-group btn-group-sm">
    <button type="button" class="btn btn-default" ng-click="toggleCommentArea(expense)"><span class="glyphicon glyphicon-comment"></span></button>
    <button type="button" class="btn btn-default" ng-show="{{status=='Pending'}}" ng-click="setStatus(expense,'Rejected')"><span class="glyphicon glyphicon-remove"></span></button>
    <button type="button" class="btn btn-default" ng-show="{{status=='Pending'}}" ng-click="setStatus(expense,'Approved')"><span class="glyphicon glyphicon-ok"></span></button>
    </div>
    <h4>{{employees[expense.user].name}} <small>{{status}}</small></h4>
    <h6>{{expense.title}}: &#8377; {{expense.amount}}</h6>
    <p ng-repeat="c in expense.comments"><q>{{c.comment}}</q> - {{c.name}}</p>
    <div ng-show="expense.showComment">
    <textarea ng-model="newComment.comment" placeholder="Enter your comment" style="width: 100%; margin-top: 10px; border: solid 1px #CCC; padding: 10px"></textarea><br/>
    <button ng-click="addNewComment(expense, newComment)" class="btn btn-primary" style="margin-top: 10px">Add Comment</button>
    </div>
    <hr/>
    </div>
    </div>
    </div>
    <div class="date-detail" ng-show="showReimbursementForm" >
    <header><h4>Apply for a reimbursement</h4><hr/></header>
    <form role="form">
    <div class="form-group">
    <label for="reimbursementReason">Reason for reimbursement</label>
    <input type="text" class="form-control" id="reimbursementReason" placeholder="Enter description" ng-model="reimbursement.reason">
    </div>
    <div class="form-group">
    <label for="reimbursementAmount">Amount for reimbursement</label>
    <input type="number" class="form-control" id="reimbursementAmount" placeholder="Enter amount (INR)" ng-model="reimbursement.amount">
    </div>

    <div class="form-group">
    <label for="reimbursementDate">Date occurred</label>
    <input type="date" class="form-control" id="reimbursementDate" ng-model="reimbursement.date">
    </div>
    <div class="form-group">
    <label for="reimbursementAttachment">Attach a reciept</label>
    <input type="file" id="reimbursementAttachment" ng-model="reimbursement.file">
    <!--<p class="help-block">Example block-level help text here.</p>-->
    </div>
    <button class="btn btn-primary" ng-click="applyReimbursement(reimbursement)">Submit</button>
    </form>
    </div>
    <div id="footer">
    <a href="#aimee" ng-click="login(0)">Login Aimee</a> |
    <a href="#joanne" ng-click="login(1)">Login Joanne</a> |
    <a href="#joanne" ng-click="resetTestData()">Reset test data</a>
    </div>
    </body>
    </html>
    242 changes: 242 additions & 0 deletions jsbin.ewoCogu.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,242 @@
    var ang = angular.module('expense',['ui.bootstrap']);

    ang.controller('CalendarController',['$scope', function($scope) {
    $scope.calendarStart = new Date();
    $scope.dates = [];
    $scope.weeks = [];
    $scope.selectedDay=null;
    $scope.showReimbursementForm = false;
    $scope.currentUser = null;
    $scope.unapprovedExpenses = 0;

    if(sessionStorage.expenses===undefined)
    sessionStorage.expenses = JSON.stringify('[]');

    $scope.expenses = JSON.parse(sessionStorage.expenses);

    $scope.dateClass = function(date) {
    return sameMonth($scope.calendarStart, date) ? '' : 'past';
    };

    $scope.addNewComment = function(expense, newComment) {
    expense.comments.push({name: $scope.currentUser.name, comment: newComment.comment});
    expense.showComment = false;
    newComment.comment = "";
    };

    $scope.selectDay = function($event,day) {
    if($scope.selectedDay==day || day.empty) {
    $scope.selectedDay = null;
    } else {
    $scope.selectedDay = day;
    }
    };

    $scope.toggleCommentArea = function(expense) {
    expense.showComment = !expense.showComment;
    };

    $scope.toggleReimbursementForm = function() {
    $scope.showReimbursementForm = !$scope.showReimbursementForm;
    };

    $scope.applyReimbursement = function(reimbursement) {
    var _date = new Date(reimbursement.date);


    $scope.expenses.push({ title: reimbursement.reason, amount: reimbursement.amount, comments: [],
    status: "Pending", user: $scope.currentUser.id, incurred: _date.getTime() });

    $scope.showReimbursementForm = false;
    saveExpenses();
    };


    // setup calendar with a month starting on Sunday
    $scope.$watch('calendarStart', function(date) {
    // Ensure there is a real date
    if (date === undefined || date === null)
    return;

    // Start on Sunday
    var cDay = new Date(date);
    cDay.setDate(date.getDate() - date.getDay());

    var dates = [];
    var sM = date.getMonth();
    var sY = date.getYear();

    // Loop through month
    while(sameMonth(cDay,date) || cDay < date) {
    dates.push(new Date(cDay));
    cDay.setDate(cDay.getDate() + 1);
    }

    // Add on until saturday
    while(cDay.getDay() !== 0) {
    dates.push(new Date(cDay));
    cDay.setDate(cDay.getDate() + 1);
    }

    $scope.dates = dates;
    $scope.weeks = createWeeks(dates);
    });

    $scope.expenseStatusCount = function(status, expenses) {
    if(status === "Approved") {
    return "approved";
    } else if (status === "Rejected") {
    return "rejected";
    } else {
    return "requested";
    }
    };

    $scope.setStatus = function(expense, status) {
    expense.status = status;
    saveExpenses();
    };

    function sameMonth(date1, date2) {
    return date1.getMonth() == date2.getMonth() &&
    date1.getYear() == date2.getYear();
    }

    function createWeeks(dates) {
    var cweek = [];
    var weeks = [];
    for(var i in dates) {
    if(dates[i].getDay() === 0) {
    cWeek = [];
    weeks.push(cWeek);

    }
    cWeek.push(dates[i]);
    }
    return weeks;
    }


    /********************************************
    BEGIN: Handle month picker
    ********************************************/
    $scope.$watch('calendarStart', function (date) {
    if(date !== undefined && date !== null) {
    $scope.monthString = date.getFullYear() + '-' + pad(date.getMonth() + 1,2);
    }
    });

    $scope.$watch('monthString', function (monthString) {
    if(monthString !== undefined) {
    $scope.calendarStart = new Date(monthString + "-01");
    }
    });

    function pad(n, width, z) {
    z = z || '0';
    n = n + '';
    return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
    }

    /********************************************
    END: Handle month picker
    ********************************************/

    /********************************************
    BEGIN: Test Data
    ********************************************/

    var aimee = {
    name: "Aimee Mann",
    pictureUrl: "http://lorempixel.com/400/400/people/9/",
    id: 0,
    manages: []
    };

    var joanne = {
    name: "Joanne Farr",
    pictureUrl: "http://lorempixel.com/400/400/people/1/",
    id: 1,
    manages: [0]
    };

    $scope.currentUser = aimee;
    $scope.employees = [aimee, joanne];


    $scope.$watch('dates', updateDateDetails, true);
    $scope.$watch('expenses', updateDateDetails, true);

    function updateDateDetails() {
    if($scope.dates == [] || $scope.expenses == [])
    return;

    var personal = _.chain($scope.expenses)
    .where({user: $scope.currentUser.id})
    .groupBy('incurred')
    .value();

    var staff = _.chain($scope.expenses)
    .filter(function (expense) {
    return _.contains($scope.currentUser.manages, expense.user)
    ;})
    .groupBy('incurred')
    .value();

    for(var i in $scope.dates) {
    var thisDate = $scope.dates[i];
    var thisTime = thisDate.getTime();

    var empty = true;

    if(personal[thisTime] !== undefined) {
    empty = false;
    thisDate.personal = _.groupBy(personal[thisTime], 'status');
    } else {
    thisDate.personal = {};
    }

    if(staff[thisTime] !== undefined) {
    empty = false;
    thisDate.staff = _.groupBy(staff[thisTime], 'status');
    } else {
    thisDate.staff = {};
    }

    thisDate.travel = [];
    thisDate.empty = empty;
    }


    // set un approved personal
    $scope.unapprovedExpenses = _.chain($scope.expenses)
    .where({user: $scope.currentUser.id, status: "Pending"})
    .value().length;

    }

    var sampleTime = (new Date("12/1/2013 UTC")).getTime();

    $scope.login = function(id) {
    $scope.currentUser = $scope.employees[id];
    updateDateDetails();
    };

    $scope.resetTestData = function() {
    $scope.expenses = [tE(), tE({status: "Approved", user: 1, title: "Travel to client"})];
    saveExpenses();
    };

    function saveExpenses() {
    sessionStorage.expenses = JSON.stringify($scope.expenses);
    }

    function tE(params) {
    return _.extend({ title: "Client Lunch", amount: "1500", comments: [], status: "Pending", user: 0, incurred: sampleTime },params || {});
    }

    /********************************************
    END: Test Data
    ********************************************/

    }]);