Feature: add account entries listing

This commit is contained in:
2015-10-06 08:42:21 +00:00
parent 7b44292c96
commit 4080080cb3
5 changed files with 619 additions and 0 deletions

View File

@@ -0,0 +1,172 @@
(function(){
'use strict';
angular
.module('cloudbudget')
.filter('category', CategoryFilter)
.filter('sub_category', SubcategoryFilter)
.controller('AccountController', AccountController);
function CategoryFilter() {
return function(input, categories) {
if( !input ) {
return '';
}
var category = categories.filter(function(elt, idx) {
return elt._id === input;
});
if( category.length > 0 ) {
return category[0].label;
}
return '';
};
}
function SubcategoryFilter() {
return function(input, category_id, categories) {
if( !input || !category_id) {
return '';
}
var category = categories.filter(function(elt, idx) {
return elt._id === category_id;
})[0];
if( !category ) {
return '';
}
var res = category.sub_categories.filter( function(elt, idx) {
return elt._id === input;
});
if( res.length === 1 ) {
return res[0].label;
} else {
return '';
}
};
}
AccountController.$inject = ['$scope', '$location', '$routeParams', 'FlashService', 'AccountService'];
function AccountController($scope, $location, $routeParams, FlashService, AccountService) {
var vm = this;
$scope.calendar = {
opened: {},
dateFormat: 'dd/MM/yyyy',
dateOptions: {},
open: function($event, which) {
$event.preventDefault();
$event.stopPropagation();
$scope.calendar.opened[which] = true;
}
};
vm.dataLoading = false;
vm.entries = [];
vm.categories = [];
vm.sub_categories = [];
vm.account = undefined;
vm.create = create;
vm.drop = drop;
vm.edit = edit;
vm.updateSubCategory = updateSubCategory;
vm.updateSubCategoryEditForm = updateSubCategoryEditForm;
vm.disabledSubCategories = false;
vm.edit_sub_categories = [];
(function init() {
vm.dataLoading = true;
AccountService.details($routeParams.account_id)
.then(function(response) {
if( response.success ) {
vm.account = response.account;
vm.categories = angular.copy(vm.account.categories);
vm.categories.unshift({_id: '', label: ''});
} else {
FlashService.error(response.message);
}
vm.dataLoading = false;
});
AccountService.list($routeParams.account_id)
.then(function(response) {
if( response.success ) {
vm.entries = response.data.entries;
} else {
FlashService.error(response.message);
}
});
})();
function create() {
vm.dataLoading = true;
AccountService.create(vm.account, vm.entry)
.then( function(response) {
if( response.success) {
vm.entries = response.data.entries;
} else {
FlashService.error(response.message);
}
vm.dataLoading = false;
});
vm.entry = angular.copy({});
$scope.form.$setPristine();
};
function drop(entry) {
vm.dataLoading = true;
AccountService.drop(vm.account, entry)
.then(function(response) {
if( response.success ) {
vm.entries = response.data.entries;
} else {
FlashService.error( response.message );
}
vm.dataLoading = false;
});
};
function edit(altered, origin) {
vm.dataLoading = true;
return AccountService.edit(vm.account, origin._id, altered)
.then( function(response) {
vm.dataLoading = false;
if( response.success ) {
var index = vm.entries.map(function (item) {
return item._id;
}).indexOf(origin._id);
vm.entries[index] = response.data.entries[index];
} else {
var index = vm.entries.map(function (item) {
return item._id;
}).indexOf(origin._id);
vm.entries[index] = origin;
FlashService.error( response.message );
return false;
}
})
};
function updateSubCategory() {
vm.sub_categories = getSubCategories(vm.entry.category);
};
function updateSubCategoryEditForm(category_id) {
vm.edit_sub_categories = getSubCategories(category_id);
vm.disabledSubCategories = !vm.edit_sub_categories || vm.edit_sub_categories.length === 0;
};
function getSubCategories(category_id) {
var categories = vm.categories.filter(function(elt, idx) {
return elt._id === category_id;
});
if( categories.length === 0 ) {
return [];
} else {
return categories[0].sub_categories;
}
}
}
})();

View File

@@ -0,0 +1,96 @@
<div class="container-fluid div-striped">
<div class="row">
<form name="form" ng-submit="vm.create()" role="form">
<div class="col-sm-2">
<div class="form-group" ng-class="{'has-error': form.date.$dirty && form.date.$error.required}">
<input type="date" class="form-control input-sm" name="date" id="date"
ng-model="vm.entry.date"
placeholder="Date"
required/>
<span ng-show="form.date.$dirty && form.date.$error.required" class="help-block">Date is required</span>
</div>
</div>
<div class="col-sm-2">
<div class="form-group">
<select name="category" class="form-control input-sm" ng-change="vm.updateSubCategory()" ng-model="vm.entry.category">
<option ng-repeat="category in vm.categories" value="{{category._id}}">{{category.label}}</option>
</select>
</div>
</div>
<div class="col-sm-2">
<div class="form-group">
<select name="sub_category" class="form-control input-sm" ng-hide="!vm.entry.category || vm.sub_categories.length === 0" ng-model="vm.entry.sub_category">
<option value=""></option>
<option ng-repeat="sub_category in vm.sub_categories" value="{{sub_category._id}}">{{sub_category.label}}</option>
</select>
</div>
</div>
<div class="col-sm-2">
<div class="form-group">
<input name="label" id="label" class="form-control input-sm" ng-model="vm.entry.label" placeholder="Label" />
</div>
</div>
<div class="col-sm-2">
<div class="form-group" ng-class="{'has-error': form.amount.$dirty && form.amout.$error.required}">
<input type="number" name="amount" id="amount" class="form-control input-sm" ng-model="vm.entry.amount" placeholder="Amount" required/>
<span ng-show="form.amount.$dirty && form.amount.$error.required" class="help-block">Amount is required</span>
</div>
</div>
<div class="col-sm-2">
<button type="submit" class="btn btn-primary" ng-disabled="form.$invalid || vm.dataLoading">
<i class="fa fa-fw fa-floppy-o"></i>
</button>
<img ng-if="vm.dataLoading" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==" />
</div>
</form>
</div>
<div class="row" ng-repeat="entry in vm.entries">
<div class="col-sm-2 small">
<span e-form="editEntryForm" e-name="date"
editable-date="entry.date"
e-required>{{entry.date | date: "dd/MM/yyyy" }}</span>
</div>
<div class="col-sm-2 small">
<span e-form="editEntryForm"
e-name="category"
editable-select="entry.category"
e-ng-change="vm.updateSubCategoryEditForm($data)"
e-ng-options="category._id as category.label for category in vm.categories">{{entry.category | category:vm.categories}}</span>
</div>
<div class="col-sm-2 small">
<span e-form="editEntryForm"
e-name="sub_category"
editable-select="entry.sub_category"
e-ng-options="category._id as category.label for category in vm.edit_sub_categories"
e-ng-hide="vm.disabledSubCategories">{{entry.sub_category | sub_category:entry.category:vm.categories}}</span>
</div>
<div class="col-sm-2 small">
<span e-form="editEntryForm" e-name="label" editable-text="entry.label">{{entry.label}}</span>
</div>
<div class="col-sm-2 text-right small">
<span e-form="editEntryForm"
e-name="amount"
editable-number="entry.amount"
ng-class="{'text-danger': entry.type === 'BILL'}"
e-required>
{{entry.amount | currency }}
</span>
</div>
<div class="col-sm-2">
<form editable-form name="editEntryForm" onbeforesave="vm.edit($data, entry)" ng-show="editEntryForm.$visible" shown="inserted == entry">
<button type="submit" ng-disabled="editEntryForm.$invalid || editEntryForm.$waiting" title="Edit" class="btn btn-success">
<i class="fa fa-fw fa-floppy-o"></i>
</button>
<button type="button" ng-disabled="editEntryForm.$waiting" title="Cancel" ng-click="editEntryForm.$cancel()" class="btn btn-default">
<i class="fa fa-fw fa-ban"></i>
</button>
<a class="btn btn-danger" title="Delete" ng-disabled="editEntryForm.$waiting" ng-click="vm.drop(entry)">
<i class="fa fa-fw fa-trash"></i>
</a>
</form>
<a class="btn btn-success" ng-click="editEntryForm.$show()" ng-show="!editEntryForm.$visible">
<i class="fa fa-fw fa-pencil"></i>
</a>
</div>
</div>
</div>

View File

@@ -0,0 +1,6 @@
div.div-striped div.row:nth-of-type(odd) {
background: #e0e0e0;
}
div.div-striped div.row:nth-of-type(even) {
background: #FFFFFF;
}

View File

@@ -0,0 +1,58 @@
(function() {
'use strict';
angular
.module('cloudbudget')
.factory('AccountService', AccountService);
AccountService.$inject =['$http', 'apiRoutes'];
function AccountService($http, apiRoute) {
var service = {};
service.details = details;
service.list = list;
service.create = create;
service.drop = drop;
service.edit = edit;
return service;
function details(account_id) {
return $http.get( apiRoute.accounts + account_id)
.then(function handleSuccess(response) {
return {success: true, account: response.data};
}, handleError('Error during accounts listing'));
}
function list(account_id) {
return $http.get( apiRoute.accounts + account_id + '/entries')
.then(handleSuccess, handleError('Error listing account entries'));
}
function create(account, entry) {
return $http.post( apiRoute.accounts + account._id + '/entries', entry)
.then(handleSuccess, handleError('Error creating entry'));
}
function drop(account, entry) {
return $http.delete(apiRoute.accounts + account._id + '/entries/' + entry._id)
.then(handleSuccess, handleError('Error deleting entry'));
}
function edit(account, id, entry) {
return $http.put(apiRoute.accounts + account._id + '/entries/' + id, entry)
.then(handleSuccess, handleError('Error updating entry'));
}
function handleSuccess(response) {
return {success: true, data: response.data};
}
function handleError(error) {
return function() {
return {success: false, message: error};
};
}
}
})();