Created
December 11, 2013 08:41
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
::-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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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>₹ 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 & 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}}: ₹ {{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}}: ₹ {{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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
********************************************/ | |
}]); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment