├── e2e-tests ├── scenarios.js ├── main.spec.js ├── main.po.js └── protractor.conf.js ├── app ├── src │ ├── authentication │ │ ├── authentication.module.js │ │ ├── login │ │ │ ├── login.component.spec.js │ │ │ ├── login.html │ │ │ └── login.component.js │ │ ├── forgot │ │ │ ├── forgot.component.js │ │ │ └── forgot.html │ │ ├── register │ │ │ ├── verification │ │ │ │ ├── verification.components.js │ │ │ │ └── verification.html │ │ │ ├── register.component.js │ │ │ └── register.html │ │ ├── authentication.html │ │ └── authentication.service.js │ ├── accounts │ │ ├── account-list │ │ │ ├── account-list.module.js │ │ │ ├── account-list.component.spec.js │ │ │ └── account-list.component.js │ │ ├── loan-account-detail │ │ │ ├── loan-account-detail.module.js │ │ │ ├── loan-account-detail.component.spec.js │ │ │ ├── loan-account-detail.service.js │ │ │ └── loan-account-detail.component.js │ │ └── savings-account-detail │ │ │ ├── savings-account-detail.module.js │ │ │ ├── savings-account-detail.component.spec.js │ │ │ ├── savings-account-detail.service.js │ │ │ └── savings-account-detail.component.js │ ├── reports │ │ ├── view_reports │ │ │ ├── view_reports.service.js │ │ │ ├── view_reports.component.js │ │ │ └── view_reports.html │ │ └── run_reports │ │ │ ├── run_reports.service.js │ │ │ ├── run_reports.html │ │ │ └── run_reports.component.js │ ├── common │ │ ├── coming-soon.html │ │ ├── translate-helper │ │ │ ├── translate-helper.html │ │ │ ├── translate-helper.directive.js │ │ │ └── translate-helper.component.js │ │ ├── 404.html │ │ ├── nav.service.js │ │ ├── storage.service.js │ │ ├── directives │ │ │ └── api-validate │ │ │ │ └── api-validate.directive.js │ │ ├── factories │ │ │ └── APIRequestInterceptor.factory.js │ │ ├── account.service.js │ │ ├── main.component.js │ │ ├── main.filters.js │ │ └── main.html │ ├── help │ │ ├── help.service.js │ │ ├── help.component.js │ │ └── help.html │ ├── aboutUs │ │ ├── aboutUs.service.js │ │ ├── aboutUs.component.js │ │ └── aboutUs.html │ ├── shares-application │ │ ├── shares-application.service.js │ │ ├── shares-application.component.js │ │ └── shares-application.html │ ├── savings-application │ │ ├── savings-application.service.js │ │ ├── savings-application.component.js │ │ └── savings-application.html │ ├── charges │ │ ├── charges.service.js │ │ ├── charges.component.js │ │ └── charges.html │ ├── recent-transactions │ │ ├── recent-transactions.service.js │ │ ├── recent-transactions.component.js │ │ └── recent-transactions.html │ ├── transfers │ │ ├── transfers.service.js │ │ ├── review-transfer-dialog │ │ │ ├── review-transfer-dialog.html │ │ │ └── review-transfer-dialog.component.js │ │ ├── transfers.html │ │ └── transfers.component.js │ ├── loan-application │ │ ├── loan-application.service.js │ │ ├── loan-application.html │ │ └── loan-application.component.js │ ├── beneficiaries │ │ ├── beneficiaries.service.js │ │ ├── beneficiaries-add │ │ │ ├── review-beneficiary-dialog │ │ │ │ ├── review-beneficiary-dialog.html │ │ │ │ └── review-beneficiary-dialog.component.js │ │ │ ├── beneficiaries-add.component.js │ │ │ └── beneficiaries-add.html │ │ ├── beneficiaries-edit │ │ │ ├── beneficiaries-edit.html │ │ │ └── beneficiaries-edit.component.js │ │ └── beneficiaries-list │ │ │ ├── beneficiaries-list.component.js │ │ │ └── beneficiaries-list.html │ ├── tpt │ │ ├── review-tpt-dialog │ │ │ ├── review-tpt-dialog.html │ │ │ └── review-tpt-dialog.component.js │ │ ├── tpt.component.js │ │ └── tpt.html │ └── dashboard │ │ └── dashboard.html ├── index.scss ├── favicon.ico ├── assets │ ├── images │ │ ├── cover.png │ │ ├── toolbar.png │ │ ├── MifosX_logo.png │ │ ├── ic_close_white_24px.svg │ │ ├── ic_person_black_24px.svg │ │ ├── ic_person_white_24px.svg │ │ ├── ic_remove_red_eye_black_24px.svg │ │ └── ic_search_black_24px.svg │ └── stylesheets │ │ ├── 404.scss │ │ └── _table.scss ├── app.css ├── app.modules.js ├── global-translations │ ├── locale-hi.json │ └── locale-en.json ├── app.constants.js ├── index.html ├── app.config.js └── 404.html ├── .bowerrc ├── .travis.yml ├── .gitignore ├── gulp ├── deploy.js ├── watch.js ├── unit-tests.js ├── e2e-tests.js ├── server.js ├── styles.js ├── proxy.js ├── inject.js └── build.js ├── .github ├── PULL_REQUEST_TEMPLATE.md └── ISSUE_TEMPLATE.md ├── .eslintrc ├── gulpfile.js ├── karma.conf.js ├── Dockerfile ├── .jshintrc ├── LICENSE ├── bower.json ├── README.md ├── package.json └── CONTRIBUTING.md /e2e-tests/scenarios.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/src/authentication/authentication.module.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/index.scss: -------------------------------------------------------------------------------- 1 | // injector 2 | // endinjector 3 | -------------------------------------------------------------------------------- /app/src/accounts/account-list/account-list.module.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/src/authentication/login/login.component.spec.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/src/reports/view_reports/view_reports.service.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "4" 4 | -------------------------------------------------------------------------------- /app/src/accounts/account-list/account-list.component.spec.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/src/accounts/loan-account-detail/loan-account-detail.module.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/src/common/coming-soon.html: -------------------------------------------------------------------------------- 1 | This page is still under construction -------------------------------------------------------------------------------- /app/src/accounts/savings-account-detail/savings-account-detail.module.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/src/accounts/loan-account-detail/loan-account-detail.component.spec.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/src/accounts/savings-account-detail/savings-account-detail.component.spec.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openMF/web-self-service-app/HEAD/app/favicon.ico -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | bower_components/ 3 | .sass-cache/ 4 | .tmp/ 5 | dist/ 6 | .idea/ 7 | .publish/ 8 | 9 | -------------------------------------------------------------------------------- /app/assets/images/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openMF/web-self-service-app/HEAD/app/assets/images/cover.png -------------------------------------------------------------------------------- /app/assets/images/toolbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openMF/web-self-service-app/HEAD/app/assets/images/toolbar.png -------------------------------------------------------------------------------- /app/assets/images/MifosX_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openMF/web-self-service-app/HEAD/app/assets/images/MifosX_logo.png -------------------------------------------------------------------------------- /app/app.css: -------------------------------------------------------------------------------- 1 | md-toolbar .md-menu{ 2 | margin: 0 1rem; 3 | } 4 | #sidebar-menu .md-button{ 5 | text-transform: capitalize; 6 | } 7 | #sidebar-menu__account-types{ 8 | margin-left: 1rem; 9 | } -------------------------------------------------------------------------------- /gulp/deploy.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | var ghPages = require('gulp-gh-pages'); 5 | 6 | gulp.task('deploy', function() { 7 | return gulp.src('./dist/**/*') 8 | .pipe(ghPages()); 9 | }); 10 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for contributing to Mifos web self-service. 2 | 3 | ##Description 4 | Describe the changes that were made. 5 | 6 | ##Related issues and discussion 7 | -{Issue Number} 8 | 9 | ##Screenshots/GIFs, if any: -------------------------------------------------------------------------------- /e2e-tests/main.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('The main view', function () { 4 | var page; 5 | 6 | beforeEach(function () { 7 | browser.get('http://localhost:3000/index.html'); 8 | page = require('./main.po'); 9 | }); 10 | 11 | }); 12 | -------------------------------------------------------------------------------- /app/assets/images/ic_close_white_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "plugins": [ 4 | "angular" 5 | ], 6 | "rules": { 7 | "angular/controller-as": 0 8 | }, 9 | "env": { 10 | "browser": true, 11 | "jasmine": true, 12 | "jquery": true 13 | }, 14 | "globals": { 15 | "angular": true 16 | } 17 | } -------------------------------------------------------------------------------- /app/assets/images/ic_person_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/assets/images/ic_person_white_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /e2e-tests/main.po.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file uses the Page Object pattern to define the main page for tests 3 | * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var MainPage = function() { 9 | }; 10 | 11 | module.exports = new MainPage(); 12 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | gulp.paths = { 6 | src: 'app', 7 | dist: 'dist', 8 | tmp: '.tmp', 9 | e2e: 'e2e-tests' 10 | }; 11 | 12 | require('require-dir')('./gulp'); 13 | 14 | gulp.task('default', ['clean'], function () { 15 | gulp.start('build'); 16 | }); 17 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(config) { 4 | 5 | config.set({ 6 | autoWatch : false, 7 | 8 | frameworks: ['jasmine'], 9 | 10 | browsers : ['PhantomJS'], 11 | 12 | plugins : [ 13 | 'karma-phantomjs-launcher', 14 | 'karma-jasmine' 15 | ] 16 | }); 17 | }; 18 | -------------------------------------------------------------------------------- /gulp/watch.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var paths = gulp.paths; 6 | 7 | gulp.task('watch', ['inject'], function () { 8 | gulp.watch([ 9 | paths.src + '/*.html', 10 | paths.src + '/{app,components}/**/*.scss', 11 | paths.src + '/{app,components}/**/*.js', 12 | 'bower.json' 13 | ], ['inject']); 14 | }); 15 | -------------------------------------------------------------------------------- /app/src/common/translate-helper/translate-helper.html: -------------------------------------------------------------------------------- 1 | Change Language: 2 | 3 | 4 | English 5 | हिन्दी 6 | 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ##Description 2 | Provide a brief overview of the enhancement or issue. 3 | 4 | ##Steps to reproduce 5 | Please mention the steps to reproduce the error/issue. 6 | 7 | ##Expected Behaviour 8 | 9 | ##Actual Behaviour 10 | 11 | ##Settings: 12 | -Browser used: 13 | 14 | ##Screenshots/GIFs, if any: 15 | Please attach screenshots/GIFs of the error/issue. -------------------------------------------------------------------------------- /app/app.modules.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService', [ 5 | 'ngAnimate', 6 | 'ngCookies', 7 | 'ngSanitize', 8 | 'ngResource', 9 | 'ui.router', 10 | 'ngMaterial', 11 | 'ngMessages', 12 | 'nvd3', 13 | 'md.data.table', 14 | 'pascalprecht.translate' 15 | ]) 16 | 17 | })(); -------------------------------------------------------------------------------- /app/assets/images/ic_remove_red_eye_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/assets/images/ic_search_black_24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/global-translations/locale-hi.json: -------------------------------------------------------------------------------- 1 | { 2 | "login.heading.logintoyouraccount": "अपने अकाउंट में लॉग इन करें", 3 | "login.btn.login": "लॉग इन करें", 4 | 5 | "nav.msg.welcome": "नमस्ते,", 6 | "nav.label.accounts": "खातों", 7 | "nav.label.recenttransactions": "हालिया लेनदेन", 8 | "nav.label.charges": "शुल्क", 9 | "nav.label.transfers": "ट्रान्सफर", 10 | "nav.label.aboutus": "हमारे बारे में", 11 | "nav.label.help": "सहायता" 12 | } -------------------------------------------------------------------------------- /app/src/authentication/forgot/forgot.component.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('ForgotPwdCtrl', ['$scope', '$state', '$mdToast', 'AuthService', 'AccountService', ForgotPwdCtrl]); 6 | 7 | /** 8 | * @module ForgotPwdCtrl 9 | * @description 10 | * Handles Forgot Password 11 | */ 12 | function ForgotPwdCtrl() { 13 | 14 | } 15 | 16 | })(); 17 | -------------------------------------------------------------------------------- /app/src/help/help.service.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .service('HelpService', ['$q', '$http', '$rootScope', '$state', '$resource', HelpService]); 6 | 7 | function HelpService ($q, $http, $rootScope, $state, $resource) { 8 | 9 | this.getFAQ = function () { 10 | return $resource(''); // enter the URL of the FAQ 11 | } 12 | 13 | 14 | 15 | } 16 | })(); -------------------------------------------------------------------------------- /app/src/aboutUs/aboutUs.service.js: -------------------------------------------------------------------------------- 1 | (function (){ 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .service('AboutUsService', ['$q', '$http', '$rootScope', '$state', '$resource', AboutUsService]); 6 | 7 | function AboutUsService($q,$http,$rootScope,$state,$resource){ 8 | 9 | this.getOrgDetails = function () { 10 | return $resource(''); // enter the URL of the organisations details. 11 | }; 12 | } 13 | })(); -------------------------------------------------------------------------------- /app/src/shares-application/shares-application.service.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .service('SharesApplicationService', ['$resource', 'BASE_URL', SharesApplicationService]); 6 | 7 | /** 8 | * @module SharesApplicationService 9 | * @description 10 | * Service required for Shares Application 11 | */ 12 | function SharesApplicationService() { 13 | 14 | 15 | } 16 | 17 | })(); -------------------------------------------------------------------------------- /app/src/common/404.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
404
4 |
Not found :(
5 |
Sorry but we couldn’t find the page you are looking for
6 |
7 | Go back to home 8 |
9 |
-------------------------------------------------------------------------------- /app/src/savings-application/savings-application.service.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .service('SavingsApplicationService', ['$resource', 'BASE_URL', SavingsApplicationService]); 6 | 7 | /** 8 | * @module SavingsApplicationService 9 | * @description 10 | * Service required for Savings Application 11 | */ 12 | function SavingsApplicationService() { 13 | 14 | 15 | } 16 | 17 | })(); -------------------------------------------------------------------------------- /app/app.constants.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | 6 | .constant("BASE_URL", "https://mobile.openmf.org/fineract-provider/api/v1") 7 | 8 | .constant('AUTH_EVENTS', { 9 | updateUser: 'update-user', 10 | notAuthorized: 'auth-not-authorized', 11 | notAuthenticated: 'auth-not-authenticated' 12 | }) 13 | 14 | 15 | .constant("TENANT_IDENTIFIER", "default") 16 | 17 | 18 | .constant('USER_ROLES', { 19 | user: 'USER' 20 | }); 21 | })(); 22 | -------------------------------------------------------------------------------- /app/src/charges/charges.service.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | angular.module('selfService') 4 | .service('ChargesService', ['$q', '$http', '$rootScope', '$resource', 'BASE_URL', ChargesService]); 5 | 6 | function ChargesService($q, $http, $rootScope, $resource, BASE_URL) { 7 | 8 | this.getClientCharges = function (clientId) { 9 | return $resource(BASE_URL + '/self/clients/' + clientId + '/charges') 10 | } 11 | 12 | } 13 | 14 | })(); 15 | -------------------------------------------------------------------------------- /app/src/recent-transactions/recent-transactions.service.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | angular.module('selfService') 4 | .service('TransactionService', ['$q', '$http', '$rootScope', '$resource', 'BASE_URL', TransactionService]); 5 | 6 | function TransactionService($q, $http, $rootScope, $resource, BASE_URL) { 7 | 8 | this.getClientTransactions = function (clientId) { 9 | return $resource(BASE_URL + '/self/clients/' + clientId + '/transactions') 10 | } 11 | 12 | } 13 | 14 | })(); 15 | -------------------------------------------------------------------------------- /app/src/accounts/loan-account-detail/loan-account-detail.service.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | //@todo Move this service to the common folder 4 | angular.module('selfService') 5 | .service('LoanAccountService', ['$q', '$http', '$rootScope', '$resource', 'BASE_URL', LoanAccountService]); 6 | 7 | function LoanAccountService($q, $http, $rootScope, $resource, BASE_URL) { 8 | 9 | this.loanAccount = function () { 10 | return $resource(BASE_URL + '/self/loans/:id',{id: '@id'}); 11 | } 12 | } 13 | 14 | })(); 15 | -------------------------------------------------------------------------------- /app/src/common/translate-helper/translate-helper.directive.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .directive('translateHelper', translateHelper); 6 | 7 | function translateHelper() { 8 | var directive = { 9 | restrict: 'E', 10 | controller: 'translateHelperCtrl', 11 | controllerAs: 'vm', 12 | scope: {}, 13 | templateUrl: 'src/common/translate-helper/translate-helper.html' 14 | } 15 | 16 | return directive; 17 | } 18 | 19 | })(); 20 | -------------------------------------------------------------------------------- /app/src/reports/run_reports/run_reports.service.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .service('RunReportService', ['$q', '$http', '$rootScope', '$state', '$resource', 'BASE_URL', RunReportService]); 6 | 7 | function RunReportService($q, $http, $rootScope, $state, $resource, BASE_URL) { 8 | 9 | this.reports = function () { 10 | 11 | return $resource(BASE_URL + "/self/runreports/:reportName" + '?R_officeId='+ ':id', {reportName: '@reportName', id: '@id'}); 12 | 13 | 14 | } 15 | 16 | } 17 | 18 | })(); -------------------------------------------------------------------------------- /app/src/accounts/savings-account-detail/savings-account-detail.service.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | //@todo Move this service to the common folder 4 | angular.module('selfService') 5 | .service('SavingsAccountService', ['$q', '$http', '$rootScope', '$resource', 'BASE_URL', SavingsAccountService]); 6 | 7 | function SavingsAccountService($q, $http, $rootScope, $resource, BASE_URL) { 8 | 9 | this.savingsAccount = function () { 10 | return $resource(BASE_URL + '/self/savingsaccounts/:id',{id: '@id'}); 11 | } 12 | } 13 | 14 | })(); 15 | -------------------------------------------------------------------------------- /app/src/help/help.component.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('HelpCtrl', ['$scope', '$rootScope', '$state', '$stateParams','HelpService', HelpCtrl]); 6 | 7 | function HelpCtrl ($scope, $rootscope, $state, $stateParams, HelpService) { 8 | var vm=this; 9 | 10 | vm.faqData=[]; 11 | vm.getfaq = getfaq; 12 | 13 | function getfaq() { 14 | HelpService.getFAQ().get().$promise.then(function (data) { 15 | vm.faqData = data; 16 | 17 | }) 18 | } 19 | 20 | } 21 | })(); -------------------------------------------------------------------------------- /app/src/common/nav.service.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .service('navService', ['$q', navService]); 6 | 7 | function navService($q){ 8 | var menuItems = [ 9 | { 10 | name: 'Dashboard', 11 | icon: 'view_module', 12 | sref: '.dashboard' 13 | }, 14 | { 15 | name: 'Accounts', 16 | icon: 'account_balance_wallet', 17 | sref: '.clients' 18 | } 19 | ]; 20 | 21 | return { 22 | loadAllItems : function() { 23 | return $q.when(menuItems); 24 | } 25 | }; 26 | } 27 | 28 | })(); -------------------------------------------------------------------------------- /app/src/reports/view_reports/view_reports.component.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('ViewReportsCtrl', ['$scope', '$rootScope', '$state','$location', ViewReportsCtrl]); 6 | 7 | function ViewReportsCtrl($scope, $rootScope, $state, $location) { 8 | var vm = this; 9 | vm.selected = []; 10 | vm.routeTo = routeTo; 11 | 12 | function routeTo(report) { 13 | $location.path('/run_report/' + report.reportName + '/' + report.id + '/' + report.reportType); 14 | } 15 | 16 | vm.reports = []; 17 | 18 | } 19 | 20 | })(); -------------------------------------------------------------------------------- /app/src/transfers/transfers.service.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | angular.module('selfService') 4 | .service('AccountTransferService', ['$q', '$http', '$rootScope', '$resource', 'BASE_URL', AccountTransferService]); 5 | 6 | function AccountTransferService($q, $http, $rootScope, $resource, BASE_URL) { 7 | 8 | this.getTransferTemplate = function () { 9 | return $resource(BASE_URL + '/self/accounttransfers/template'); 10 | } 11 | 12 | this.transfer = function () { 13 | return $resource(BASE_URL + '/self/accounttransfers'); 14 | } 15 | 16 | } 17 | 18 | })(); 19 | -------------------------------------------------------------------------------- /app/src/common/translate-helper/translate-helper.component.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('translateHelperCtrl', ['$scope', '$rootScope', '$translate', translateHelperCtrl]); 6 | 7 | function translateHelperCtrl($scope, $rootScope, $translate) { 8 | var vm = this; 9 | vm.langCode = getLangCode(); 10 | vm.updateLang = updateLang; 11 | 12 | function getLangCode() { 13 | return $translate.use(); 14 | } 15 | 16 | function updateLang() { 17 | $translate.use(vm.langCode); 18 | } 19 | } 20 | 21 | })(); 22 | -------------------------------------------------------------------------------- /app/src/loan-application/loan-application.service.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .service('LoanApplicationService', ['$resource', 'BASE_URL', LoanApplicationService]); 6 | 7 | /** 8 | * @module LoanApplicationService 9 | * @description 10 | * Service required for Loan Application 11 | */ 12 | function LoanApplicationService($resource, BASE_URL) { 13 | 14 | this.template = function() { 15 | return $resource(BASE_URL + '/self/loans/template'); 16 | } 17 | 18 | this.loan = function() { 19 | return $resource(BASE_URL + '/self/loans'); 20 | } 21 | } 22 | 23 | })(); -------------------------------------------------------------------------------- /app/src/aboutUs/aboutUs.component.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('AboutUsCtrl', ['$scope', '$rootScope', '$state', '$stateParams', 'AboutUsService', AboutUsCtrl]); 6 | 7 | function AboutUsCtrl ($scope, $rootScope, $state, $stateParams, AboutUsService) { 8 | 9 | var vm=this; 10 | vm.org = null; // it is an array, when data is available then vm.org = {JSON data}; 11 | vm.getDetails = getDetails; 12 | 13 | function getDetails() { 14 | AboutUsService.getOrgDetails.get().$promise.then(function (data){ 15 | vm.org =data; 16 | }) 17 | } 18 | } 19 | })(); 20 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mhart/alpine-node:8.9.4 as builder 2 | 3 | RUN apk update 4 | RUN apk add git 5 | RUN mkdir -p /usr/src/app 6 | WORKDIR /usr/src/app 7 | ENV PATH /usr/src/app/node_modules/.bin:$PATH 8 | COPY package.json /usr/src/app/package.json 9 | COPY gulpfile.js /usr/src/app/gulpfile.js 10 | RUN npm install bower 11 | RUN npm install gulp-cli 12 | COPY . /usr/src/app 13 | RUN bower --allow-root install 14 | RUN npm install -f 15 | RUN npm install --save-dev gulp 16 | RUN npm install --save-dev gulp-inject 17 | RUN npm install --save-dev gulp-ruby-sass 18 | COPY gulpfile.js /usr/src/app/gulpfile.js 19 | RUN gulp build 20 | 21 | FROM nginx:1.19.3 22 | COPY --from=builder /usr/src/app/dist /usr/share/nginx/html 23 | EXPOSE 80 24 | CMD ["nginx", "-g", "daemon off;"] 25 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "camelcase": true, 6 | "curly": true, 7 | "eqeqeq": true, 8 | "immed": true, 9 | "indent": 2, 10 | "latedef": true, 11 | "newcap": true, 12 | "noarg": true, 13 | "quotmark": "single", 14 | "regexp": true, 15 | "undef": true, 16 | "unused": true, 17 | "strict": true, 18 | "trailing": true, 19 | "smarttabs": true, 20 | "white": true, 21 | "validthis": true, 22 | "globals": { 23 | "angular": false, 24 | // Angular Mocks 25 | "inject": false, 26 | // JASMINE 27 | "describe": false, 28 | "it": false, 29 | "before": false, 30 | "beforeEach": false, 31 | "after": false, 32 | "afterEach": false, 33 | "expect": false 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /e2e-tests/protractor.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var paths = require('./.yo-rc.json')['generator-gulp-angular'].props.paths; 4 | 5 | // An example configuration file. 6 | exports.config = { 7 | // The address of a running selenium server. 8 | //seleniumAddress: 'http://localhost:4444/wd/hub', 9 | //seleniumServerJar: deprecated, this should be set on node_modules/protractor/config.json 10 | 11 | // Capabilities to be passed to the webdriver instance. 12 | capabilities: { 13 | 'browserName': 'chrome' 14 | }, 15 | 16 | // Spec patterns are relative to the current working directly when 17 | // protractor is called. 18 | specs: [paths.e2e + '/**/*.js'], 19 | 20 | // Options to be passed to Jasmine-node. 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /app/src/common/storage.service.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .service('storageService', ['$q', storageService]); 6 | 7 | function storageService($q){ 8 | 9 | return { 10 | getItem: function (key) { 11 | return $q.when(window.localStorage.getItem(key)); 12 | }, 13 | setItem: function (key, value) { 14 | window.localStorage.setItem(key, value); 15 | }, 16 | getObject: function (key) { 17 | return $q.when(JSON.parse(window.localStorage.getItem(key))); 18 | }, 19 | setObject: function (key, value) { 20 | value = JSON.stringify(value); 21 | window.localStorage.setItem(key, value); 22 | }, 23 | clear: function () { 24 | window.localStorage.clear(); 25 | } 26 | }; 27 | } 28 | 29 | })(); -------------------------------------------------------------------------------- /app/src/shares-application/shares-application.component.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('SharesApplicationCtrl', ['$scope', '$filter', '$mdToast', 'AccountService', 'SharesApplicationService', SharesApplicationCtrl]); 6 | 7 | /** 8 | * @module SharesApplicationCtrl 9 | * @description 10 | * Controls Application for Shares 11 | */ 12 | function SharesApplicationCtrl($scope) { 13 | var vm = this; 14 | 15 | vm.clearForm = clearForm; 16 | vm.submit = submit; 17 | vm.form = {}; 18 | 19 | function clearForm() { 20 | $scope.shareApplicationForm.$setPristine(); 21 | $scope.shareApplicationForm.$setUntouched(); 22 | vm.form = {}; 23 | } 24 | 25 | function submit() { 26 | 27 | } 28 | 29 | } 30 | })(); -------------------------------------------------------------------------------- /app/src/common/directives/api-validate/api-validate.directive.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .directive('apiValidate', ['$compile', apiValidate]); 6 | 7 | function apiValidate($compile) { 8 | return { 9 | restrict: 'E', 10 | link: function (scope, elm) { 11 | var template = '
' + 12 | '
' + 13 | '' + 16 | '

'; 17 | elm.html('').append($compile(template)(scope)); 18 | } 19 | }; 20 | } 21 | 22 | })(); -------------------------------------------------------------------------------- /app/src/beneficiaries/beneficiaries.service.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .service('BeneficiariesService', ['$q', '$http', '$rootScope', '$state', '$resource', 'BASE_URL', BeneficiariesService]); 6 | 7 | function BeneficiariesService($q, $http, $rootScope, $state, $resource, BASE_URL) { 8 | 9 | this.getBeneficiaries = function () { 10 | return $resource(BASE_URL + '/self/beneficiaries/tpt'); 11 | }; 12 | 13 | this.template = function() { 14 | return $resource(BASE_URL + '/self/beneficiaries/tpt/template'); 15 | } 16 | 17 | this.beneficiary = function () { 18 | return $resource(BASE_URL + '/self/beneficiaries/tpt/:id',{id: '@id'},{ 19 | update: { 20 | method: 'PUT' 21 | } 22 | }); 23 | } 24 | } 25 | 26 | })(); -------------------------------------------------------------------------------- /app/src/savings-application/savings-application.component.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('SavingsApplicationCtrl', ['$scope', '$filter', '$mdToast', 'AccountService', 'SavingsApplicationService', SavingsApplicationCtrl]); 6 | 7 | /** 8 | * @module SavingsApplicationCtrl 9 | * @description 10 | * Controls Application for Savings 11 | */ 12 | function SavingsApplicationCtrl($scope) { 13 | var vm = this; 14 | vm.form = {}; 15 | 16 | vm.clearForm = clearForm; 17 | vm.submit = submit; 18 | vm.form = {}; 19 | 20 | function clearForm() { 21 | $scope.savingsApplicationForm.$setPristine(); 22 | $scope.savingsApplicationForm.$setUntouched(); 23 | vm.form = {}; 24 | } 25 | 26 | function submit() { 27 | 28 | } 29 | } 30 | })(); -------------------------------------------------------------------------------- /gulp/unit-tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var $ = require('gulp-load-plugins')(); 6 | 7 | var wiredep = require('wiredep'); 8 | 9 | var paths = gulp.paths; 10 | 11 | function runTests (singleRun, done) { 12 | var bowerDeps = wiredep({ 13 | directory: 'bower_components', 14 | exclude: ['bootstrap-sass-official'], 15 | dependencies: true, 16 | devDependencies: true 17 | }); 18 | 19 | var testFiles = bowerDeps.js.concat([ 20 | paths.src + '/{app,components}/**/*.js' 21 | ]); 22 | 23 | gulp.src(testFiles) 24 | .pipe($.karma({ 25 | configFile: 'karma.conf.js', 26 | action: (singleRun)? 'run': 'watch' 27 | })) 28 | .on('error', function (err) { 29 | // Make sure failed tests cause gulp to exit non-zero 30 | throw err; 31 | }); 32 | } 33 | 34 | gulp.task('test', function (done) { runTests(true /* singleRun */, done) }); 35 | gulp.task('test:auto', function (done) { runTests(false /* singleRun */, done) }); 36 | -------------------------------------------------------------------------------- /app/assets/stylesheets/404.scss: -------------------------------------------------------------------------------- 1 | #error-404 { 2 | 3 | background: #f1f1f1; 4 | 5 | .content { 6 | width: 90%; 7 | max-width: 512px; 8 | 9 | .error-code { 10 | font-size: 112px; 11 | text-align: center; 12 | line-height: 1; 13 | margin-bottom: 16px; 14 | font-weight: 500; 15 | } 16 | 17 | .error-code-msg { 18 | font-size: 74px; 19 | text-align: center; 20 | line-height: 1; 21 | margin-bottom: 8px; 22 | font-weight: 500; 23 | } 24 | 25 | .message { 26 | font-size: 24px; 27 | text-align: center; 28 | color: rgba(0, 0, 0, 0.54); 29 | } 30 | 31 | .search { 32 | width: 100%; 33 | height: 56px; 34 | line-height: 56px; 35 | margin: 48px auto 16px auto; 36 | padding: 16px; 37 | background: #FFFFFF; 38 | 39 | input { 40 | padding: 0 0 0 16px; 41 | } 42 | } 43 | 44 | .back-link { 45 | font-size: 15px; 46 | text-align: center; 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /gulp/e2e-tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var $ = require('gulp-load-plugins')(); 6 | 7 | var browserSync = require('browser-sync'); 8 | 9 | var paths = gulp.paths; 10 | 11 | // Downloads the selenium webdriver 12 | gulp.task('webdriver-update', $.protractor.webdriver_update); 13 | 14 | gulp.task('webdriver-standalone', $.protractor.webdriver_standalone); 15 | 16 | function runProtractor (done) { 17 | 18 | gulp.src(paths.e2e + '/**/*.js') 19 | .pipe($.protractor.protractor({ 20 | configFile: 'protractor.conf.js', 21 | })) 22 | .on('error', function (err) { 23 | // Make sure failed tests cause gulp to exit non-zero 24 | throw err; 25 | }) 26 | .on('end', function () { 27 | // Close browser sync server 28 | browserSync.exit(); 29 | done(); 30 | }); 31 | } 32 | 33 | gulp.task('protractor', ['protractor:src']); 34 | gulp.task('protractor:src', ['serve:e2e', 'webdriver-update'], runProtractor); 35 | gulp.task('protractor:dist', ['serve:e2e-dist', 'webdriver-update'], runProtractor); 36 | -------------------------------------------------------------------------------- /app/src/help/help.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | FAQ 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | {{item.Question}} 15 |

16 |
17 |
18 | 19 |
20 | arrow_forward_ios 21 | {{item.Answer}} 22 |
23 |
24 |
25 |
26 |
27 |
28 |
-------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 flatlogic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "self-service-app", 3 | "description": "Self Service Application", 4 | "homepage": "", 5 | "license": "MIT", 6 | "version": "1.2.0", 7 | "dependencies": { 8 | "jquery": "^3.2.1", 9 | "angular": "^1.8.2", 10 | "angular-material": "^1.1.4", 11 | "angular-animate": "^1.6.5", 12 | "angular-cookies": "^1.6.5", 13 | "angular-touch": "^1.6.5", 14 | "angular-sanitize": "^1.6.5", 15 | "angular-ui-router": "^1.0.6", 16 | "angular-nvd3": "^1.0.9", 17 | "angular-translate-storage-cookie": "2.19.0", 18 | "angular-translate-storage-local": "2.19.0", 19 | "angular-resource": "^1.6.5", 20 | "angular-material-data-table": "^0.10.10", 21 | "angular-translate": "^2.19.0", 22 | "angular-translate-loader-static-files": "^2.19.0", 23 | "components-font-awesome": "^4.7.0", 24 | "ngmap":"" 25 | }, 26 | "overrides": { 27 | "components-font-awesome": { 28 | "main": [ 29 | "./css/font-awesome.css", 30 | "./fonts/*" 31 | ] 32 | } 33 | }, 34 | "devDependencies": { 35 | "angular-mocks": "^1.6.5" 36 | }, 37 | "resolutions": { 38 | "angular": "1.7.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/common/factories/APIRequestInterceptor.factory.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .factory('APIRequestInterceptor', ['$rootScope', '$q', APIRequestInterceptor]); 6 | 7 | function APIRequestInterceptor($rootScope, $q) { 8 | return { 9 | request: function(config) { 10 | $rootScope.blockUI = true; 11 | $rootScope.respERROR = null; 12 | return $q.resolve(config); 13 | }, 14 | requestError: function (rejection) { 15 | $rootScope.blockUI = false; 16 | $rootScope.respERROR = null; 17 | return $q.reject(rejection); 18 | }, 19 | response: function(response) { 20 | $rootScope.blockUI = false; 21 | $rootScope.respERROR = null; 22 | return $q.resolve(response); 23 | }, 24 | responseError: function(response) { 25 | $rootScope.blockUI = false; 26 | $rootScope.respERROR = response; 27 | return $q.reject(response); 28 | } 29 | } 30 | } 31 | 32 | })(); 33 | -------------------------------------------------------------------------------- /app/src/charges/charges.component.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('ChargesCtrl', ['$scope', '$rootScope', '$stateParams', 'AccountService', 'ChargesService', ChargesCtrl]); 6 | 7 | function ChargesCtrl($scope, $rootScope, $stateParams, AccountService, ChargesService) { 8 | 9 | var vm = this; 10 | vm.loadingCharges = true; 11 | vm.charges = {}; 12 | vm.onPaginate = onPaginate; 13 | vm.page = 1; 14 | vm.query = { 15 | limit: 5, 16 | offset: 0 17 | } 18 | 19 | vm.getCharges = getCharges(vm.query); 20 | 21 | function getCharges(query){ 22 | AccountService.getClientId().then(function (clientId){ 23 | ChargesService.getClientCharges(clientId).get(query).$promise.then(function (res) { 24 | vm.loadingCharges = false; 25 | vm.charges = res; 26 | }); 27 | }); 28 | } 29 | 30 | function onPaginate(offset,limit) { 31 | getCharges(angular.extend({}, vm.query, {offset: (offset - 1) * limit, limit: limit})); 32 | } 33 | 34 | } 35 | })(); -------------------------------------------------------------------------------- /app/src/reports/run_reports/run_reports.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | {{vm.reportName}} 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
{{columnHeader.columnName}}
{{col}}
24 |
25 |
26 |
27 |
28 |
-------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mifos Self Service App 2 | 3 | ## Getting started 4 | You can follow this README or you can follow this [video](https://mifosforge.jira.com/wiki/spaces/docs/pages/498794497/Developer+Environment+Setup+for+Online+Banking+App+2.0). 5 | 6 | Clone the project: 7 | 8 | $ git clone https://github.com/openMF/web-self-service-app.git 9 | 10 | Install dependencies: 11 | 12 | $ cd web-self-service-app 13 | 14 | $ npm install 15 | $ bower install 16 | 17 | Install gem 'sass' 18 | 19 | Make sure that you have '''ruby''' installed (if not goto https://www.ruby-lang.org/en/documentation/installation/ ). 20 | 21 | $ gem install sass 22 | 23 | Run development web-server: 24 | 25 | $ gulp serve 26 | 27 | Use these credentials to logIn `username: selfservice password: password` 28 | 29 | 30 | ## Contributing Guidelines: 31 | * Contributors must follow these [guidelines](https://github.com/openMF/web-self-service-app/blob/develop/CONTRIBUTING.md) 32 | 33 | ## Features 34 | 35 | * AngularJS 36 | * Angular UI Router 37 | * Angular Material 38 | * Sass styles 39 | * Gulp build 40 | * Stylish, clean, responsive layout with original design 41 | * BrowserSync for the ease of development 42 | 43 | ## Deploy to Github pages 44 | 45 | $ gulp build 46 | $ gulp deploy 47 | -------------------------------------------------------------------------------- /app/src/recent-transactions/recent-transactions.component.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('RecentTransactionCtrl', ['$scope', '$rootScope', '$stateParams', 'AccountService', 'TransactionService', RecentTransactionCtrl]); 6 | 7 | function RecentTransactionCtrl($scope, $rootScope, $stateParams, AccountService, TransactionService) { 8 | 9 | var vm = this; 10 | vm.loadingTransactions = true; 11 | vm.recenttransactions = {}; 12 | vm.onPaginate = onPaginate; 13 | vm.page = 1; 14 | vm.query = { 15 | limit: 5, 16 | offset: 0 17 | } 18 | 19 | vm.getTransactions = getTransactions(vm.query); 20 | 21 | function getTransactions(query){ 22 | AccountService.getClientId().then(function (clientId){ 23 | TransactionService.getClientTransactions(clientId).get(query).$promise.then(function (res) { 24 | vm.loadingTransactions = false; 25 | vm.recenttransactions = res; 26 | }); 27 | }); 28 | } 29 | 30 | function onPaginate(offset,limit) { 31 | getTransactions(angular.extend({}, vm.query, {offset: (offset - 1) * limit, limit: limit})); 32 | } 33 | 34 | } 35 | })(); -------------------------------------------------------------------------------- /app/src/beneficiaries/beneficiaries-add/review-beneficiary-dialog/review-beneficiary-dialog.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
5 |

Review Beneficiary

6 | 7 | 8 | 10 | 11 |
12 |
13 | 14 | 15 |
16 |

17 | Account Type: {{vm.accountType(vm.addBeneficiaryFormData.accountType)}} 18 |

19 |

20 | Account Number: {{vm.addBeneficiaryFormData.accountNumber}} 21 |

22 |

23 | Office Name: {{vm.addBeneficiaryFormData.officeName}} 24 |

25 |

26 | Transfer Limit: {{vm.addBeneficiaryFormData.transferLimit}} 27 |

28 |

29 | Beneficiary Name: {{vm.addBeneficiaryFormData.name}} 30 |

31 |
32 |
33 | 34 | 35 | Cancel 36 | 37 | 38 | Add Beneficiary 39 | 40 | 41 |
42 |
-------------------------------------------------------------------------------- /app/src/reports/run_reports/run_reports.component.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('RunReportCtrl', ['$http', '$scope', '$rootScope','$state', '$stateParams', '$resource', '$location', 'dateFilter', 'BASE_URL', '$sce', 'RunReportService', RunReportCtrl]); 6 | 7 | function RunReportCtrl($http, $scope, $rootScope, $state, $stateParams, $resource, $location, dateFilter, BASE_URL, $sce, RunReportService) { 8 | var vm = this; 9 | 10 | 11 | vm.reportName = $stateParams.name; 12 | vm.id = $stateParams.id; 13 | vm.reportData = {}; 14 | vm.reportData.columnHeaders = []; 15 | 16 | vm.isDecimal = isDecimal 17 | 18 | 19 | RunReportService.reports().get({reportName: vm.reportName, id: vm.id}).$promise.then(function(data) { 20 | vm.reportData = data; 21 | vm.reportData.columnHeaders = data.columnHeaders; 22 | }); 23 | 24 | function isDecimal (index) { 25 | if(vm.reportData.columnHeaders && vm.reportData.columnHeaders.length > 0){ 26 | for(var i=0; i 2 |
3 | 4 | 5 | 6 | No details to show 7 | 8 | 9 | 10 |
11 |
12 |
13 |
14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 |

{{vm.org.name}}

24 |
25 |
26 |
27 |
28 |
29 | 30 | 31 |

{{'label.heading.aboutUs' | translate}}

32 |

{{vm.org.description}}

33 |
34 |
35 |
36 |
37 | -------------------------------------------------------------------------------- /gulp/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var paths = gulp.paths; 6 | 7 | var util = require('util'); 8 | 9 | var browserSync = require('browser-sync'); 10 | 11 | var middleware = require('./proxy'); 12 | 13 | function browserSyncInit(baseDir, files, browser) { 14 | browser = browser === undefined ? 'default' : browser; 15 | 16 | var routes = null; 17 | if(baseDir === paths.src || (util.isArray(baseDir) && baseDir.indexOf(paths.src) !== -1)) { 18 | routes = { 19 | '/bower_components': 'bower_components' 20 | }; 21 | } 22 | 23 | browserSync.instance = browserSync.init(files, { 24 | startPath: '/', 25 | ghostMode:false, 26 | server: { 27 | baseDir: baseDir, 28 | middleware: middleware, 29 | routes: routes 30 | }, 31 | browser: browser 32 | }); 33 | } 34 | 35 | gulp.task('serve', ['watch'], function () { 36 | browserSyncInit([ 37 | paths.tmp + '/serve', 38 | paths.src 39 | ], [ 40 | paths.src + '/src/**/*.js', 41 | paths.src + '/src/**/*.html', 42 | paths.src + '/assets/images/**/*', 43 | paths.tmp + '/serve/*.html', 44 | paths.tmp + '/serve/**/*.html', 45 | paths.tmp + '/serve/**/*.css' 46 | ]); 47 | }); 48 | 49 | gulp.task('serve:dist', ['build'], function () { 50 | browserSyncInit(paths.dist); 51 | }); 52 | 53 | gulp.task('serve:e2e', ['inject'], function () { 54 | browserSyncInit([paths.tmp + '/serve', paths.src], null, []); 55 | }); 56 | 57 | gulp.task('serve:e2e-dist', ['build'], function () { 58 | browserSyncInit(paths.dist, null, []); 59 | }); 60 | -------------------------------------------------------------------------------- /gulp/styles.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var paths = gulp.paths; 6 | 7 | var $ = require('gulp-load-plugins')(); 8 | 9 | gulp.task('styles', function () { 10 | 11 | var sassOptions = { 12 | style: 'expanded', 13 | 'sourcemap=none': true 14 | }; 15 | 16 | var injectFiles = gulp.src([ 17 | paths.src + '/assets/stylesheets/**/*.scss', 18 | '!' + paths.src + '/index.scss' 19 | ], {read: false}); 20 | 21 | var injectOptions = { 22 | transform: function (filePath) { 23 | filePath = filePath.replace(paths.src + '/', ''); 24 | filePath = filePath.replace(paths.src + '/components/', '../components/'); 25 | return '@import \'' + filePath + '\';'; 26 | }, 27 | starttag: '// injector', 28 | endtag: '// endinjector', 29 | addRootSlash: false 30 | }; 31 | 32 | var indexFilter = $.filter('index.scss'); 33 | 34 | return gulp.src(paths.src + '/index.scss') 35 | .pipe(indexFilter) 36 | .pipe($.inject(injectFiles, injectOptions)) 37 | .pipe(indexFilter.restore()) 38 | .pipe($.rubySass(sassOptions) 39 | .on('error', function (err) { 40 | console.error('Error!', err.message); 41 | }) 42 | ) 43 | 44 | .pipe($.autoprefixer()) 45 | .on('error', function handleError(err) { 46 | console.error(err.toString()); 47 | this.emit('end'); 48 | }) 49 | .pipe(gulp.dest(paths.tmp + '/serve/styles/')) 50 | .pipe(gulp.dest(paths.dist + '/styles/')); 51 | }); 52 | -------------------------------------------------------------------------------- /app/src/authentication/register/verification/verification.components.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('VerificationCtrl', ['$scope', '$state', '$mdToast', 'AuthService', '$location', VerificationCtrl]); 6 | 7 | 8 | function VerificationCtrl($scope, $state, $mdToast, AuthService, $location) { 9 | var vm = this; 10 | vm.verifyData = {}; 11 | 12 | /* function clearForm() { 13 | $scope.form.$setPristine(); 14 | $scope.form.$setUntouched(); 15 | vm.verifyData={}; 16 | 17 | }*/ 18 | 19 | $scope.submit = function() { 20 | AuthService.verifyUser(vm.verifyData).then(function () { 21 | $mdToast.show( 22 | $mdToast.simple() 23 | .textContent('User has been successfully registered') 24 | .position('top right') 25 | ); 26 | $location.path('/login'); 27 | vm.clearForm(); 28 | }, function (resp) { 29 | var errors = ''; 30 | if(resp.data){ 31 | errors = resp.data.errors.map(function (data) { 32 | return data.defaultUserMessage; 33 | }); 34 | errors.join(' '); 35 | } 36 | $mdToast.show( 37 | $mdToast.simple() 38 | .textContent('Error in creating user: ' + errors) 39 | .position('top right') 40 | ); 41 | 42 | }); 43 | 44 | } 45 | 46 | } 47 | 48 | })(); 49 | -------------------------------------------------------------------------------- /app/src/tpt/review-tpt-dialog/review-tpt-dialog.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
5 |

Review Transfer

6 | 7 | 8 | 9 | 10 |
11 |
12 | 13 | 14 |
15 |

16 | Transfer To:
17 | Account Number: {{ vm.transferFormData.toAccount.accountNo }} 18 |

19 |

20 | Transfer From:
21 | Account Number: {{ vm.transferFormData.fromAccount.accountNo }} 22 |

23 |

24 | Amount: {{ vm.transferFormData.amount }} 25 |

26 |

27 | Transfer Date: {{ vm.transferFormData.transferDate }} 28 |

29 |

30 | Remark: {{ vm.transferFormData.remark }} 31 |

32 |
33 |
34 | 35 | 36 | Cancel 37 | 38 | 39 | Transfer Now 40 | 41 | 42 |
43 |
-------------------------------------------------------------------------------- /app/src/transfers/review-transfer-dialog/review-transfer-dialog.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
5 |

Review Transfer

6 | 7 | 8 | 9 | 10 |
11 |
12 | 13 | 14 |
15 |

16 | Transfer To:
17 | Account Number: {{ vm.transferFormData.toAccount.accountNo }} 18 |

19 |

20 | Transfer From:
21 | Account Number: {{ vm.transferFormData.fromAccount.accountNo }} 22 |

23 |

24 | Amount: {{ vm.transferFormData.amount }} 25 |

26 |

27 | Transfer Date: {{ vm.transferFormData.transferDate }} 28 |

29 |

30 | Remark: {{ vm.transferFormData.remark }} 31 |

32 |
33 |
34 | 35 | 36 | Cancel 37 | 38 | 39 | Transfer Now 40 | 41 | 42 |
43 |
-------------------------------------------------------------------------------- /app/src/authentication/forgot/forgot.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 7 | 8 |
Recover your password
9 | 10 |
11 | 12 | 14 |
15 |
16 | Email field is required 17 |
18 |
19 | Email must be a valid e-mail address 20 |
21 |
22 |
23 | 24 | 26 | SEND RESET LINK 27 | 28 |
29 | 30 | 33 |
34 |
35 |
-------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Self-Service-App", 3 | "version": "1.3.0", 4 | "dependencies": { 5 | "ngmap": "^1.18.5" 6 | }, 7 | "devDependencies": { 8 | "browser-sync": "~1.7.1", 9 | "chalk": "~0.5.1", 10 | "del": "~0.1.3", 11 | "eslint": "^4.0.0", 12 | "eslint-plugin-angular": "^2.4.2", 13 | "gulp": "~3.9.0", 14 | "gulp-angular-filesort": "~1.0.4", 15 | "gulp-angular-templatecache": "~1.4.2", 16 | "gulp-autoprefixer": "~2.0.0", 17 | "gulp-concat": "^2.6.1", 18 | "gulp-consolidate": "~0.1.2", 19 | "gulp-csso": "~0.2.9", 20 | "gulp-filter": "~1.0.2", 21 | "gulp-flatten": "~0.0.4", 22 | "gulp-gh-pages": "^0.5.4", 23 | "gulp-hash-filename": "^1.2.0", 24 | "gulp-inject": "~1.0.2", 25 | "gulp-jshint": "~1.9.0", 26 | "gulp-karma": "~0.0.4", 27 | "gulp-load-plugins": "~0.7.1", 28 | "gulp-minify-html": "~0.1.7", 29 | "gulp-ng-annotate": "~1.0.0", 30 | "gulp-protractor": "~0.0.11", 31 | "gulp-rename": "~1.2.0", 32 | "gulp-replace": "~0.5.0", 33 | "gulp-rev": "~2.0.1", 34 | "gulp-rev-replace": "~0.3.1", 35 | "gulp-ruby-sass": "~0.7.1", 36 | "gulp-size": "~1.1.0", 37 | "gulp-uglify": "~1.0.1", 38 | "gulp-useref": "~1.0.2", 39 | "http-proxy": "~1.7.0", 40 | "jshint-stylish": "~1.0.0", 41 | "karma-jasmine": "~0.3.1", 42 | "karma-phantomjs-launcher": "~0.1.4", 43 | "main-bower-files": "~2.4.0", 44 | "protractor": "~1.4.0", 45 | "require-dir": "^0.3.2", 46 | "run-sequence": "^1.2.2", 47 | "uglify-save-license": "~0.4.1", 48 | "wiredep": "~2.2.0" 49 | }, 50 | "engines": { 51 | "node": ">=0.10.0" 52 | }, 53 | "scripts": { 54 | "init": "npm install", 55 | "install": "npm install -g bower && bower install", 56 | "lint": "eslint app/", 57 | "test": "npm run lint" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/beneficiaries/beneficiaries-add/review-beneficiary-dialog/review-beneficiary-dialog.component.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('ReviewBeneficiaryDialogCtrl', ['$scope', '$rootScope', '$state', '$stateParams', '$filter', '$mdDialog', '$mdToast', 'addBeneficiaryFormData', 'BeneficiariesService', ReviewBeneficiaryDialogCtrl]) 6 | 7 | function ReviewBeneficiaryDialogCtrl($scope, $rootScope, $state, $stateParams, $filter, $mdDialog, $mdToast, addBeneficiaryFormData, BeneficiariesService) { 8 | 9 | var vm = this; 10 | vm.addBeneficiaryFormData = Object.assign({}, addBeneficiaryFormData); 11 | vm.cancel = cancel; 12 | vm.accountType = accountType; 13 | vm.add = add; 14 | 15 | function cancel() { 16 | $mdDialog.cancel(); 17 | } 18 | 19 | function accountType(id) { 20 | if (1 == id) { 21 | return 'Loan Account'; 22 | } else { 23 | return 'Savings Account'; 24 | } 25 | } 26 | 27 | function add() { 28 | // Sending 29 | BeneficiariesService.beneficiary().save(vm.addBeneficiaryFormData).$promise.then(function () { 30 | $mdDialog.hide("success"); 31 | $mdToast.show( 32 | $mdToast.simple() 33 | .textContent('Beneficiary Added Successfully') 34 | .position('top right') 35 | ); 36 | vm.clearForm(); 37 | }, function (resp) { 38 | var errors = ''; 39 | if (resp.data) { 40 | errors = resp.data.errors.map(function (data) { 41 | return data.defaultUserMessage; 42 | }); 43 | errors.join(' '); 44 | } 45 | $mdToast.show( 46 | $mdToast.simple() 47 | .textContent('Error in Adding Beneficiary: ' + errors) 48 | .position('top right') 49 | ); 50 | $mdDialog.hide("error"); 51 | }); 52 | } 53 | } 54 | })(); -------------------------------------------------------------------------------- /app/src/common/account.service.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | //@todo Move this service to the common folder 4 | angular.module('selfService') 5 | .service('AccountService', ['$http', '$resource', 'BASE_URL', 'storageService', AccountService]); 6 | 7 | function AccountService($http, $resource, BASE_URL, storageService) { 8 | 9 | /** 10 | * Get the clients associated with the current user's account. 11 | * 12 | */ 13 | this.getClients = function () { 14 | return $resource(BASE_URL + '/self/clients/'); 15 | }; 16 | 17 | this.getAllAccounts = function (clientId) {//@todo rename this getClientAccounts 18 | //@todo update this to return $resource(BASE_URL+'/self/clients/'+id+'/accounts'); and test 19 | return $resource(BASE_URL + '/self/clients/' + clientId + '/accounts'); 20 | }; 21 | 22 | this.getClient = function (id) { 23 | return $resource(BASE_URL + '/self/clients/' + id); 24 | } 25 | 26 | this.getClientImage = function (id) { 27 | return $http({ 28 | method: 'GET', 29 | url: BASE_URL + '/self/clients/' + id + '/images' 30 | }); 31 | } 32 | 33 | this.getClientCharges = function (id) { 34 | return $resource(BASE_URL + '/self/clients/' + id + '/charges?pendingPayment=true'); 35 | } 36 | 37 | this.getClientAccounts = function (id) { 38 | return $resource(BASE_URL + '/self/clients/' + id + '/accounts'); 39 | } 40 | 41 | this.getLoanAccount = function (id) { 42 | return $resource(BASE_URL + '/self/loans/' + id); 43 | } 44 | 45 | this.setClientId = function (id) { 46 | storageService.setObject('client_id', id); 47 | } 48 | 49 | this.getClientId = function () { 50 | return storageService.getItem('client_id'); 51 | } 52 | 53 | } 54 | 55 | })(); 56 | -------------------------------------------------------------------------------- /gulp/proxy.js: -------------------------------------------------------------------------------- 1 | /*jshint unused:false */ 2 | 3 | /*************** 4 | 5 | This file allow to configure a proxy system plugged into BrowserSync 6 | in order to redirect backend requests while still serving and watching 7 | files from the web project 8 | 9 | IMPORTANT: The proxy is disabled by default. 10 | 11 | If you want to enable it, watch at the configuration options and finally 12 | change the `module.exports` at the end of the file 13 | 14 | ***************/ 15 | 16 | 'use strict'; 17 | 18 | var httpProxy = require('http-proxy'); 19 | var chalk = require('chalk'); 20 | 21 | /* 22 | * Location of your backend server 23 | */ 24 | var proxyTarget = 'http://server/context/'; 25 | 26 | var proxy = httpProxy.createProxyServer({ 27 | target: proxyTarget 28 | }); 29 | 30 | proxy.on('error', function(error, req, res) { 31 | res.writeHead(500, { 32 | 'Content-Type': 'text/plain' 33 | }); 34 | 35 | console.error(chalk.red('[Proxy]'), error); 36 | }); 37 | 38 | /* 39 | * The proxy middleware is an Express middleware added to BrowserSync to 40 | * handle backend request and proxy them to your backend. 41 | */ 42 | function proxyMiddleware(req, res, next) { 43 | /* 44 | * This test is the switch of each request to determine if the request is 45 | * for a static file to be handled by BrowserSync or a backend request to proxy. 46 | * 47 | * The existing test is a standard check on the files extensions but it may fail 48 | * for your needs. If you can, you could also check on a context in the url which 49 | * may be more reliable but can't be generic. 50 | */ 51 | if (/\.(html|css|js|png|jpg|jpeg|gif|ico|xml|rss|txt|eot|svg|ttf|woff|cur)(\?((r|v|rel|rev)=[\-\.\w]*)?)?$/.test(req.url)) { 52 | next(); 53 | } else { 54 | proxy.web(req, res); 55 | } 56 | } 57 | 58 | /* 59 | * This is where you activate or not your proxy. 60 | * 61 | * The first line activate if and the second one ignored it 62 | */ 63 | 64 | //module.exports = [proxyMiddleware]; 65 | module.exports = []; 66 | -------------------------------------------------------------------------------- /app/src/authentication/register/verification/verification.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 7 | 8 |
Verification
9 | 10 |
11 | 12 | 14 |
15 |
16 | RequestID is required 17 |
18 |
19 |
20 | 21 | 23 |
24 |
25 | Authentication Token is required 26 |
27 |
28 |
29 | 30 | 32 | VERIFY 33 | 34 | 35 | CANCEL 36 | 37 |
38 |
39 |
40 |
-------------------------------------------------------------------------------- /app/src/authentication/login/login.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Self Service

5 |

Self Service is designed by the Mifos Initiative - a global community that aims to 6 | speed-up the elimination of poverty by enabling organizations to more effectively and efficiently 7 | deliver responsible financial services to the world’s poor and unbanked.

8 |
9 |
10 | 39 |
40 | -------------------------------------------------------------------------------- /app/src/reports/view_reports/view_reports.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | {{'label.headping.reports' | translate}} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | Hold tight loading Reports... 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 31 | 32 | 33 | 34 | 35 | 36 |
{{'label.heading.name' | translate}}{{'label.heading.type' | translate}}{{'label.heading.category' | translate}}
{{report.reportName}}{{report.reportType}}{{report.reportCategory}}
37 |
38 |
39 |
40 |
-------------------------------------------------------------------------------- /app/src/beneficiaries/beneficiaries-add/beneficiaries-add.component.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('BeneficiariesAddCtrl', ['$scope', '$state', '$stateParams', '$filter', '$mdDialog', '$mdToast', 'BeneficiariesService', BeneficiariesAddCtrl]); 6 | 7 | function BeneficiariesAddCtrl($scope, $state, $stateParams, $filter, $mdDialog, $mdToast, BeneficiariesService) { 8 | 9 | var vm = this; 10 | vm.addBeneficiaryFormData = { 11 | "locale": "en_GB" 12 | }; 13 | vm.accountTypeOptions = []; 14 | vm.getBeneficiaryTemplate = getBeneficiaryTemplate(); 15 | vm.clearForm = clearForm; 16 | vm.submit = submit; 17 | 18 | function getBeneficiaryTemplate() { 19 | BeneficiariesService.template().get().$promise.then(function (data) { 20 | vm.accountTypeOptions = data.accountTypeOptions; 21 | }) 22 | } 23 | 24 | function clearForm() { 25 | $scope.addBeneficiaryForm.$setPristine(); 26 | $scope.addBeneficiaryForm.$setUntouched(); 27 | vm.addBeneficiaryFormData = { 28 | "locale": "en_GB" 29 | }; 30 | } 31 | 32 | function submit(ev) { 33 | $mdDialog.show({ 34 | controller: 'ReviewBeneficiaryDialogCtrl', 35 | controllerAs: 'vm', 36 | templateUrl: 'src/beneficiaries/beneficiaries-add/review-beneficiary-dialog/review-beneficiary-dialog.html', 37 | parent: angular.element(document.body), 38 | targetEvent: ev, 39 | locals: {addBeneficiaryFormData: vm.addBeneficiaryFormData}, 40 | clickOutsideToClose: true 41 | }).then(function (result) { 42 | if (result === "success"){ 43 | clearForm(); 44 | } 45 | }, function() { 46 | clearForm(); 47 | $mdToast.show( 48 | $mdToast.simple() 49 | .textContent('Add Beneficiary Cancelled') 50 | .position('top right') 51 | ); 52 | }); 53 | } 54 | } 55 | })(); -------------------------------------------------------------------------------- /app/src/authentication/authentication.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Self Service

5 |

Self Service is designed by the Mifos Initiative - a global community that aims to speed-up the elimination of poverty by enabling organizations to more effectively and efficiently deliver responsible financial services to the world’s poor and unbanked.

6 |
7 |
8 | 40 |
41 | -------------------------------------------------------------------------------- /app/src/authentication/authentication.service.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .service('AuthService', ['$q', '$http', '$rootScope', '$state', '$resource', 'storageService', 'BASE_URL', 'USER_ROLES', AuthService]); 6 | 7 | function AuthService($q, $http, $rootScope, $state, $resource, storageService, BASE_URL, USER_ROLES) { 8 | 9 | var role = '', 10 | userData = '', 11 | isAuthenticated = false; 12 | 13 | storageService.getObject("user_profile").then(function (data) { 14 | if (data) { 15 | isAuthenticated = true; 16 | role = USER_ROLES.user; 17 | userData = data; 18 | } 19 | }) 20 | 21 | this.setUser = function (res) { 22 | storageService.setObject('user_profile', res); 23 | isAuthenticated = true; 24 | userData = res; 25 | role = USER_ROLES.user; 26 | } 27 | 28 | this.getUser = function() { 29 | return userData; 30 | } 31 | 32 | this.isAuthenticated = function () { 33 | return isAuthenticated; 34 | }; 35 | 36 | this.role = function () { 37 | return role; 38 | } 39 | 40 | this.isAuthorized = function (authorizedRoles) { 41 | if (!angular.isArray(authorizedRoles)) { 42 | authorizedRoles = [authorizedRoles]; 43 | } 44 | return (this.isAuthenticated() && authorizedRoles.indexOf(role) !== -1); 45 | } 46 | 47 | //Resource for REST APIs 48 | this.doLogin = function() { 49 | return $resource(BASE_URL +'/self/authentication'); 50 | } 51 | 52 | this.logout = function() { 53 | role = ''; 54 | userData = ''; 55 | isAuthenticated = false; 56 | storageService.clear(); 57 | $state.go('login'); 58 | } 59 | 60 | this.register = function(data) { 61 | return $http.post(BASE_URL + '/self/registration',data); 62 | } 63 | 64 | this.verifyUser = function(data){ 65 | return $http.post(BASE_URL + '/self/registration/user',data); 66 | } 67 | 68 | } 69 | 70 | })(); 71 | -------------------------------------------------------------------------------- /app/src/common/main.component.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | angular.module('selfService') 4 | .controller('MainCtrl', ['navService', '$mdSidenav', '$mdBottomSheet', '$log', '$q', '$state', '$mdToast', '$scope', 'AuthService', 'AccountService', MainCtrl]); 5 | 6 | function MainCtrl(navService, $mdSidenav, $mdBottomSheet, $log, $q, $state, $mdToast, $scope, AuthService, AccountService) { 7 | var vm = this; 8 | 9 | vm.menuItems = []; 10 | vm.profileImage = null; 11 | 12 | vm.selectItem = selectItem; 13 | vm.toggleItemsList = toggleItemsList; 14 | vm.toggleRightSidebar = toggleRightSidebar; 15 | vm.logout = logout; 16 | 17 | vm.profile = getUserData(); 18 | 19 | 20 | navService.loadAllItems().then(function (menuItems) { 21 | vm.menuItems = [].concat(menuItems); 22 | }); 23 | 24 | function toggleRightSidebar() { 25 | $mdSidenav('right').toggle(); 26 | } 27 | 28 | function toggleItemsList() { 29 | var pending = $mdBottomSheet.hide() || $q.when(true); 30 | 31 | pending.then(function () { 32 | $mdSidenav('left').toggle(); 33 | }); 34 | } 35 | 36 | function selectItem(itemName) { 37 | vm.title = itemName; 38 | vm.toggleItemsList(); 39 | } 40 | 41 | function getUserData() { 42 | AccountService.getClientId().then(function (clientId) { 43 | vm.clientId = clientId; 44 | getClient(clientId); 45 | getClientImage(clientId); 46 | }); 47 | } 48 | 49 | function getClient(clientId) { 50 | AccountService.getClient(clientId).get().$promise.then( function (data) { 51 | vm.profile = data; 52 | }) 53 | } 54 | 55 | function getClientImage(clientId) { 56 | AccountService.getClientImage(clientId).then( function (resp) { 57 | vm.profileImage = resp.data; 58 | }).catch(function() { 59 | // Not Found Profile image 60 | vm.profileImage = null; 61 | }); 62 | } 63 | 64 | function logout() { 65 | AuthService.logout(); 66 | } 67 | 68 | } 69 | 70 | })(); 71 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mifos - Self Service Application 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 30 |
31 | 32 |
33 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /app/src/authentication/register/register.component.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('RegisterCtrl', ['$scope', '$state', '$mdToast', 'AuthService', '$location', RegisterCtrl]); 6 | 7 | /** 8 | * @module RegisterCtrl 9 | * @description 10 | * Handles Registration of self service user 11 | */ 12 | function RegisterCtrl($scope, $state, $mdToast, AuthService, $location) { 13 | var vm = this; 14 | vm.clearForm = clearForm; 15 | 16 | vm.form={ 17 | "authenticationMode" :"email" 18 | }; 19 | 20 | 21 | function clearForm() { 22 | $scope.form.$setPristine(); 23 | $scope.form.$setUntouched(); 24 | vm.form = { 25 | "authenticationMode" :"email" 26 | }; 27 | 28 | } 29 | 30 | $scope.submit = function() { 31 | AuthService.register(vm.form).then(function () { 32 | $mdToast.show( 33 | $mdToast.simple() 34 | .textContent('Confirmation email is sent') // The success part is not working as the response 35 | .position('top right') // is not in JSON format 36 | ); 37 | vm.clearForm(); 38 | }, function (resp) { 39 | var errors = ''; 40 | if(resp.data){ 41 | errors = resp.data.errors.map(function (data) { 42 | return data.defaultUserMessage; 43 | }); 44 | errors.join(' '); 45 | }if(errors!=''){ 46 | $mdToast.show( 47 | $mdToast.simple() 48 | .textContent('Error in creating user: ' + errors) 49 | .position('top right') 50 | ); 51 | } 52 | else{ 53 | $mdToast.show( 54 | $mdToast.simple() 55 | .textContent('Confirmation email is sent') 56 | .position('top right') 57 | ); 58 | $location.path('/verify'); 59 | vm.clearForm(); 60 | } 61 | 62 | 63 | }); 64 | 65 | } 66 | } 67 | 68 | })(); 69 | -------------------------------------------------------------------------------- /gulp/inject.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var paths = gulp.paths; 6 | 7 | var $ = require('gulp-load-plugins')(); 8 | 9 | var wiredep = require('wiredep').stream; 10 | 11 | gulp.task('inject:build', ['styles'], function () { 12 | var injectStyles = gulp.src( 13 | paths.dist + '/styles/*.css', 14 | {read: false} 15 | ); 16 | 17 | var injectScripts = gulp.src([ 18 | paths.dist + '/js/*.js' 19 | ]).pipe($.angularFilesort()); 20 | 21 | var injectOptions = { 22 | ignorePath: [paths.dist], 23 | addRootSlash: false 24 | }; 25 | 26 | var wiredepOptions = { 27 | fileTypes: { 28 | html: { 29 | replace: { 30 | js: function(filePath) { 31 | return ''; 32 | }, 33 | css: function(filePath) { 34 | return ''; 35 | } 36 | } 37 | } 38 | } 39 | }; 40 | 41 | return gulp.src(paths.src + '/*.html') 42 | .pipe(wiredep(wiredepOptions)) 43 | .pipe($.inject(injectStyles, injectOptions)) 44 | .pipe($.inject(injectScripts, injectOptions)) 45 | .pipe(gulp.dest(paths.dist)); 46 | }); 47 | 48 | gulp.task('inject', ['styles'], function () { 49 | 50 | var injectStyles = gulp.src([ 51 | paths.tmp + '/serve/**/*.css', 52 | '!' + paths.tmp + '/serve/app/vendor.css' 53 | ], {read: false}); 54 | 55 | var injectScripts = gulp.src([ 56 | paths.src + '/**/*.js', 57 | '!' + paths.src + '/src/**/*.spec.js', 58 | '!' + paths.src + '/src/**/*.mock.js' 59 | ]).pipe($.angularFilesort()); 60 | 61 | var injectOptions = { 62 | ignorePath: [paths.src, paths.tmp + '/serve'], 63 | addRootSlash: false 64 | }; 65 | 66 | var wiredepOptions = { 67 | directory: 'bower_components', 68 | exclude: [/bootstrap\.css/, /foundation\.css/] 69 | }; 70 | 71 | return gulp.src(paths.src + '/*.html') 72 | .pipe($.inject(injectStyles, injectOptions)) 73 | .pipe($.inject(injectScripts, injectOptions)) 74 | .pipe(wiredep(wiredepOptions)) 75 | .pipe(gulp.dest(paths.tmp + '/serve')); 76 | 77 | }); 78 | -------------------------------------------------------------------------------- /app/src/tpt/tpt.component.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('TPTCtrl', ['$scope', '$rootScope', '$stateParams', '$filter', '$mdDialog', '$mdDateLocale', '$mdToast', 'AccountTransferService', TPTCtrl]); 6 | 7 | function TPTCtrl($scope, $rootScope, $stateParams, $filter, $mdDialog, $mdDateLocale, $mdToast, AccountTransferService) { 8 | 9 | var vm = this; 10 | vm.fromAccountOptions = []; 11 | vm.toAccountOptions = []; 12 | vm.transferFormData = getTransferFormDataObj() 13 | 14 | vm.getTransferTemplate = getTransferTemplate(); 15 | vm.clearForm = clearForm; 16 | vm.submit = submit; 17 | 18 | // FORMAT THE DATE FOR THE DATEPICKER 19 | $mdDateLocale.formatDate = function (date) { 20 | return $filter('date')(date, "dd-MM-yyyy"); 21 | }; 22 | 23 | function getTransferFormDataObj() { 24 | return { 25 | transferDate: new Date() 26 | }; 27 | } 28 | 29 | function getTransferTemplate() { 30 | AccountTransferService.getTransferTemplate().get({type: "tpt"},function (data) { 31 | vm.fromAccountOptions = data.fromAccountOptions; 32 | vm.toAccountOptions = data.toAccountOptions; 33 | }); 34 | } 35 | 36 | function clearForm() { 37 | vm.transferFormData = getTransferFormDataObj(); 38 | $scope.transferForm.$setPristine(); 39 | $scope.transferForm.$setUntouched(); 40 | } 41 | 42 | function submit(ev) { 43 | $mdDialog.show({ 44 | controller: 'ReviewTPTDialogCtrl', 45 | controllerAs: 'vm', 46 | templateUrl: 'src/tpt/review-tpt-dialog/review-tpt-dialog.html', 47 | parent: angular.element(document.body), 48 | targetEvent: ev, 49 | locals: {transferFormData: vm.transferFormData}, 50 | clickOutsideToClose: true 51 | }).then(function (result) { 52 | if(result === "success"){ 53 | clearForm(); 54 | } 55 | }, function () { 56 | clearForm(); 57 | $mdToast.show( 58 | $mdToast.simple() 59 | .textContent('Transfer Cancelled') 60 | .position('top right') 61 | ); 62 | }); 63 | } 64 | 65 | 66 | } 67 | })(); -------------------------------------------------------------------------------- /app/src/accounts/savings-account-detail/savings-account-detail.component.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('SavingsAccountViewCtrl', ['$state', '$stateParams', '$filter', 'SavingsAccountService', SavingsAccountViewCtrl]); 6 | 7 | /** 8 | * @module SavingsAccountViewCtrl 9 | * @description 10 | * Handles the individial savings account detail page 11 | */ 12 | function SavingsAccountViewCtrl($state, $stateParams, $filter, SavingsAccountService) { 13 | 14 | var vm = this; 15 | vm.loadingSavingsAccount = true; 16 | 17 | /** 18 | * @name statusClass 19 | * @type {string} 20 | * @description Stores the status class of savings account 21 | */ 22 | vm.statusClass = ''; 23 | 24 | /** 25 | * @name savingsAccountDetails 26 | * @type {object} 27 | * @description Stores the savings account details from server 28 | */ 29 | vm.savingsAccountDetails = getSavingsDetail($stateParams.id); 30 | 31 | /** 32 | * @name transactions 33 | * @type {Array} 34 | */ 35 | vm.transactions = []; 36 | 37 | vm.getStatusClass = getStatusClass; 38 | vm.deposit = deposit; 39 | vm.transfer = transfer; 40 | 41 | /** 42 | * @method getSavingsDetail 43 | * @description Gets savings account detail from server 44 | * @param id {number} Savings Account id 45 | */ 46 | function getSavingsDetail(id) { 47 | SavingsAccountService.savingsAccount().get({id: id, associations: 'transactions,charges'}).$promise.then(function(res) { 48 | vm.loadingSavingsAccount = false; 49 | vm.savingsAccountDetails = res; 50 | vm.transactions = res.transactions; 51 | getStatusClass(); 52 | }); 53 | } 54 | 55 | function getStatusClass() { 56 | var statusClass = $filter('StatusLookup')(vm.savingsAccountDetails.status.code); 57 | statusClass = 'bg_' + statusClass; 58 | if(vm.savingsAccountDetails.subStatus.id !== 0) { 59 | statusClass = $filter('StatusLookup')(vm.savingsAccountDetails.status.code+vm.savingsAccountDetails.subStatus.value); 60 | } 61 | 62 | vm.statusClass = statusClass; 63 | } 64 | 65 | function deposit() { 66 | $state.go('app.transfers', { 67 | toAccount: vm.savingsAccountDetails 68 | }); 69 | } 70 | 71 | function transfer() { 72 | $state.go('app.transfers', { 73 | fromAccount: vm.savingsAccountDetails 74 | }); 75 | } 76 | } 77 | })(); -------------------------------------------------------------------------------- /app/src/accounts/account-list/account-list.component.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('AccountCtrl', ['$scope', '$rootScope', '$state', 'AccountService', 'AuthService', AccountCtrl]); 6 | 7 | function AccountCtrl($scope, $rootScope, $state, AccountService, AuthService) { 8 | 9 | var vm = this; 10 | vm.selected = []; 11 | vm.getAccounts = getAccounts; 12 | vm.onPaginate = onPaginate; 13 | vm.onReorder = onReorder; 14 | vm.routeTo = routeTo; 15 | vm.userData = AuthService.getUser(); 16 | vm.clientId = getClient();//@todo check if this is behind the 2 calls 17 | vm.accounts = []; 18 | vm.loanAccounts = []; 19 | vm.savingsAccounts = []; 20 | vm.shareAccounts = []; 21 | vm.loadingAccountInfo = true; 22 | vm.tabIndex = sessionStorage.getItem("tab"); 23 | 24 | 25 | vm.query = { 26 | limit: 5, 27 | offset: 1 28 | }; 29 | 30 | function getClient() { 31 | AccountService.getClientId().then(function (clientId) { 32 | vm.clientId = clientId; 33 | getAccounts(clientId); 34 | }); 35 | } 36 | 37 | function getAccounts(accountNo) { 38 | AccountService.getAllAccounts(accountNo).get().$promise.then(function (res) { 39 | vm.loanAccounts = res.loanAccounts; 40 | vm.savingsAccounts = res.savingsAccounts; 41 | vm.shareAccounts = res.shareAccounts; 42 | vm.loadingAccountInfo = false; 43 | }); 44 | } 45 | 46 | function onPaginate(offset, limit) { 47 | getAccounts(angular.extend({}, vm.query, {offset: offset, limit: limit})); 48 | } 49 | 50 | function onReorder(order) { 51 | getAccounts(angular.extend({}, vm.query, {order: order})); 52 | } 53 | 54 | function routeTo(accountType, id) { 55 | var routingSlug = 'viewloanaccount'; 56 | if ('savings' == accountType) { 57 | routingSlug = 'viewsavingsaccount'; 58 | sessionStorage.setItem("tab", "1"); 59 | } else if ('loan' == accountType) { 60 | routingSlug = 'viewloanaccount'; 61 | sessionStorage.setItem("tab", "0"); 62 | } else { 63 | routingSlug = 'viewshareaccount'; 64 | sessionStorage.setItem("tab", "2"); 65 | } 66 | $state.go('app.'+routingSlug, {id: id}); 67 | } 68 | } 69 | 70 | })(); 71 | -------------------------------------------------------------------------------- /app/src/accounts/loan-account-detail/loan-account-detail.component.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('LoanAccountViewCtrl', ['$state', '$stateParams', '$filter', 'LoanAccountService', LoanAccountViewCtrl]); 6 | 7 | /** 8 | * @module LoanAccountViewCtrl 9 | * @description 10 | * Handles the Loan Account Details Page. 11 | */ 12 | function LoanAccountViewCtrl($state, $stateParams, $filter, LoanAccountService) { 13 | 14 | var vm = this; 15 | 16 | /** 17 | * @name loadingLoanAccountInfo 18 | * @description flag to check whether account info is loaded or not 19 | * @type {boolean} 20 | */ 21 | vm.loadingLoanAccountInfo = true; 22 | 23 | /** 24 | * @name loanAccountDetails 25 | * @type {object} 26 | * @description To store the loan Account details returned by server 27 | */ 28 | vm.loanAccountDetails = getLoanDetails($stateParams.id); 29 | 30 | /** 31 | * @name statusClass 32 | * @type {string} 33 | * @description To store the css class for loan status [active, pending, ...] 34 | */ 35 | vm.statusClass = ''; 36 | 37 | vm.repaymentSchedule = {}; 38 | 39 | vm.makePayment = makePayment; 40 | 41 | /** 42 | * @method getLoanDetails 43 | * @description To get the loan details from the server 44 | * @param id {number} Loan Account id 45 | */ 46 | function getLoanDetails(id) { 47 | LoanAccountService.loanAccount().get({ 48 | id: id, 49 | associations:'repaymentSchedule,transactions' 50 | }).$promise.then(function (res) { 51 | vm.loadingLoanAccountInfo = false; 52 | vm.loanAccountDetails = res; 53 | getStatusClass(); 54 | }); 55 | } 56 | 57 | /** 58 | * @method getStatusClass 59 | * @description To get the loan account status through the status lookup filter 60 | */ 61 | function getStatusClass() { 62 | var statusClass = $filter('StatusLookup')(vm.loanAccountDetails.status.code); 63 | statusClass = 'bg_' + statusClass; 64 | if (vm.loanAccountDetails.inArrears) { 65 | statusClass += 'overdue'; 66 | } 67 | vm.statusClass = statusClass; 68 | } 69 | 70 | function makePayment() { 71 | $state.go('app.transfers', { 72 | toAccount: vm.loanAccountDetails 73 | }); 74 | } 75 | } 76 | })(); -------------------------------------------------------------------------------- /app/src/beneficiaries/beneficiaries-add/beneficiaries-add.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | {{ 'label.heading.addbeneficiaries' | translate }} 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | {{ accountType.value }} 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 | {{ 'label.btn.cancel' | translate }} 36 | {{ 'label.btn.reviewBeneficiary' | translate }} 37 |
38 |
39 |
40 |
41 |
-------------------------------------------------------------------------------- /app/src/beneficiaries/beneficiaries-edit/beneficiaries-edit.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | {{ 'label.heading.editbeneficiaries' | translate }} 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | {{ accountType.value }} 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 | {{ 'label.btn.cancel' | translate }} 36 | {{ 'label.btn.editBeneficiary' | translate }} 37 |
38 |
39 |
40 |
41 |
-------------------------------------------------------------------------------- /app/src/beneficiaries/beneficiaries-list/beneficiaries-list.component.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('BeneficiariesListCtrl', ['$scope', '$rootScope', '$state', '$stateParams', '$mdDialog', '$mdToast', 'BeneficiariesService', BeneficiariesListCtrl]); 6 | 7 | function BeneficiariesListCtrl($scope, $rootScope, $state, $stateParams, $mdDialog, $mdToast, BeneficiariesService) { 8 | 9 | var vm = this; 10 | vm.loadingBeneficiaries = true; 11 | vm.beneficiaries = []; 12 | vm.beneficiariesFilter = ""; 13 | vm.page = 1; 14 | vm.query = { 15 | limit: 5, 16 | offset: 0 17 | } 18 | 19 | vm.getBeneficiaries = getBeneficiaries(); 20 | vm.addBeneficiary = addBeneficiary; 21 | vm.goToEdit = goToEdit; 22 | vm.deleteConfirm = deleteConfirm; 23 | 24 | function getBeneficiaries() { 25 | BeneficiariesService.getBeneficiaries().query().$promise.then(function(data) { 26 | vm.beneficiaries = data; 27 | vm.loadingBeneficiaries = false; 28 | }); 29 | } 30 | 31 | function addBeneficiary() { 32 | $state.go('app.addbeneficiary'); 33 | } 34 | 35 | function goToEdit(beneficiary) { 36 | $state.go('app.editbeneficiary',{ 37 | id: beneficiary.id, 38 | data: beneficiary 39 | }); 40 | } 41 | 42 | function deleteConfirm(ev, beneficiary) { 43 | var confirm = $mdDialog.confirm() 44 | .title('Are you sure you want to delete?') 45 | .textContent('This beneficiary will be removed from your account') 46 | .ariaLabel('Lucky day') 47 | .targetEvent(ev) 48 | .ok('Delete!') 49 | .cancel('Cancel'); 50 | 51 | $mdDialog.show(confirm).then(function() { 52 | BeneficiariesService.beneficiary().delete({ 53 | id: beneficiary.id 54 | }, function() { 55 | $mdToast.show( 56 | $mdToast.simple() 57 | .textContent('Beneficiary Deleted Successfully') 58 | .position('top right') 59 | ); 60 | vm.beneficiaries = vm.beneficiaries.filter(function (benef) { 61 | return benef.id !== beneficiary.id 62 | }); 63 | }); 64 | }, function() { 65 | $mdToast.show( 66 | $mdToast.simple() 67 | .textContent('Error in Deleting Beneficiary') 68 | .position('top right') 69 | ); 70 | }); 71 | } 72 | } 73 | })(); -------------------------------------------------------------------------------- /app/src/tpt/tpt.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | {{ 'label.heading.tpt' | translate }} 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | {{ toAccountOption.accountNo }} ({{toAccountOption.clientName}}) 16 | 17 | 18 | 19 | 20 | 21 | {{ fromAccountOption.accountNo }} ({{fromAccountOption.accountType.value}}) 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 | 32 |
33 | 34 | 35 | 36 | 37 |
38 | {{ 'label.btn.cancel' | translate }} 39 | {{ 'label.btn.reviewTransfer' | translate }} 40 |
41 | 42 |
43 |
44 |
45 |
-------------------------------------------------------------------------------- /app/src/tpt/review-tpt-dialog/review-tpt-dialog.component.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('ReviewTPTDialogCtrl', ['$scope', '$rootScope', '$stateParams', '$filter', '$mdDialog', '$mdToast', 'transferFormData', 'AccountTransferService', ReviewTPTDialogCtrl]); 6 | 7 | function ReviewTPTDialogCtrl($scope, $rootScope, $stateParams, $filter, $mdDialog, $mdToast, transferFormData, AccountTransferService) { 8 | 9 | var vm = this; 10 | vm.transferFormData = Object.assign({}, transferFormData); 11 | vm.cancel = cancel; 12 | vm.transfer = transfer; 13 | 14 | vm.transferFormData.transferDate = $filter('DateFormat')(transferFormData.transferDate); 15 | 16 | function cancel() { 17 | $mdDialog.cancel(); 18 | } 19 | 20 | function transfer() { 21 | // Transforming Request Data 22 | var transferData = { 23 | fromOfficeId: vm.transferFormData.fromAccount.officeId, 24 | fromClientId: vm.transferFormData.fromAccount.clientId, 25 | fromAccountType: vm.transferFormData.fromAccount.accountType.id, 26 | fromAccountId: vm.transferFormData.fromAccount.accountId, 27 | toOfficeId: vm.transferFormData.toAccount.officeId, 28 | toClientId: vm.transferFormData.toAccount.clientId, 29 | toAccountType: vm.transferFormData.toAccount.accountType.id, 30 | toAccountId: vm.transferFormData.toAccount.accountId, 31 | dateFormat: "dd MMMM yyyy", 32 | locale: "en", 33 | transferDate: vm.transferFormData.transferDate, 34 | transferAmount: "" + vm.transferFormData.amount, 35 | transferDescription: vm.transferFormData.remark 36 | } 37 | // Sending 38 | AccountTransferService.transfer().save({type: "tpt"},transferData).$promise.then(function () { 39 | $mdDialog.hide("success"); 40 | $mdToast.show( 41 | $mdToast.simple() 42 | .textContent('Transfer Completed Successfully') 43 | .position('top right') 44 | ); 45 | }, function (resp) { 46 | var errors = ''; 47 | if(resp.data){ 48 | errors = resp.data.errors.map(function (data) { 49 | return data.defaultUserMessage; 50 | }); 51 | errors.join(' '); 52 | } 53 | $mdToast.show( 54 | $mdToast.simple() 55 | .textContent('Error in Completing Transfer: ' + errors) 56 | .position('top right') 57 | ); 58 | $mdDialog.hide("error"); 59 | 60 | }); 61 | 62 | } 63 | } 64 | })(); -------------------------------------------------------------------------------- /app/src/transfers/review-transfer-dialog/review-transfer-dialog.component.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('ReviewTransferDialogCtrl', ['$scope', '$rootScope', '$stateParams', '$filter', '$mdDialog', '$mdToast', 'transferFormData', 'AccountTransferService', ReviewTransferDialogCtrl]); 6 | 7 | function ReviewTransferDialogCtrl($scope, $rootScope, $stateParams, $filter, $mdDialog, $mdToast, transferFormData, AccountTransferService) { 8 | 9 | var vm = this; 10 | vm.transferFormData = Object.assign({}, transferFormData); 11 | vm.cancel = cancel; 12 | vm.transfer = transfer; 13 | 14 | vm.transferFormData.transferDate = $filter('DateFormat')(transferFormData.transferDate); 15 | 16 | function cancel() { 17 | $mdDialog.cancel(); 18 | } 19 | 20 | function transfer() { 21 | // Transforming Request Data 22 | var transferData = { 23 | fromOfficeId: vm.transferFormData.fromAccount.officeId, 24 | fromClientId: vm.transferFormData.fromAccount.clientId, 25 | fromAccountType: vm.transferFormData.fromAccount.accountType.id, 26 | fromAccountId: vm.transferFormData.fromAccount.accountId, 27 | toOfficeId: vm.transferFormData.toAccount.officeId, 28 | toClientId: vm.transferFormData.toAccount.clientId, 29 | toAccountType: vm.transferFormData.toAccount.accountType.id, 30 | toAccountId: vm.transferFormData.toAccount.accountId, 31 | dateFormat: "dd MMMM yyyy", 32 | locale: "en", 33 | transferDate: vm.transferFormData.transferDate, 34 | transferAmount: "" + vm.transferFormData.amount, 35 | transferDescription: vm.transferFormData.remark 36 | } 37 | // Sending 38 | AccountTransferService.transfer().save(transferData).$promise.then(function () { 39 | $mdDialog.hide("success"); 40 | $mdToast.show( 41 | $mdToast.simple() 42 | .textContent('Transfer Completed Successfully') 43 | .position('top right') 44 | ); 45 | }, function (resp) { 46 | var errors = ''; 47 | if(resp.data){ 48 | errors = resp.data.errors.map(function (data) { 49 | return data.defaultUserMessage; 50 | }); 51 | errors.join(' '); 52 | } 53 | $mdToast.show( 54 | $mdToast.simple() 55 | .textContent('Error in Completing Transfer: ' + errors) 56 | .position('top right') 57 | ); 58 | $mdDialog.hide("error"); 59 | 60 | }); 61 | 62 | } 63 | } 64 | })(); -------------------------------------------------------------------------------- /app/src/beneficiaries/beneficiaries-edit/beneficiaries-edit.component.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('BeneficiariesEditCtrl', ['$scope', '$rootScope', '$state', '$stateParams', '$mdToast', 'BeneficiariesService', BeneficiariesEditCtrl]); 6 | 7 | function BeneficiariesEditCtrl($scope, $rootScope, $state, $stateParams, $mdToast, BeneficiariesService) { 8 | 9 | var vm = this; 10 | vm.editBeneficiaryFormData = { 11 | "locale": "en_GB" 12 | }; 13 | vm.beneficiary = $stateParams.data; 14 | vm.accountTypeOptions = []; 15 | vm.getBeneficiaryTemplate = getBeneficiaryTemplate(); 16 | vm.clearForm = clearForm; 17 | vm.submit = submit; 18 | 19 | function getBeneficiaryTemplate() { 20 | BeneficiariesService.template().get().$promise.then(function (data) { 21 | vm.accountTypeOptions = data.accountTypeOptions; 22 | }); 23 | 24 | if(vm.beneficiary !== null) { 25 | vm.editBeneficiaryFormData.accountType = vm.beneficiary.accountType.id; 26 | vm.editBeneficiaryFormData.accountNumber = vm.beneficiary.accountNumber; 27 | vm.editBeneficiaryFormData.officeName = vm.beneficiary.officeName; 28 | vm.editBeneficiaryFormData.transferLimit = vm.beneficiary.transferLimit; 29 | vm.editBeneficiaryFormData.name = vm.beneficiary.name; 30 | } 31 | } 32 | 33 | function clearForm() { 34 | vm.editBeneficiaryFormData = { 35 | "locale": "en_GB" 36 | }; 37 | $scope.editBeneficiaryForm.$setPristine(); 38 | $scope.addBeneficiaryForm.$setUntouched(); 39 | } 40 | 41 | function submit() { 42 | var data = { 43 | name: vm.editBeneficiaryFormData.name, 44 | transferLimit: vm.editBeneficiaryFormData.transferLimit 45 | } 46 | 47 | BeneficiariesService.beneficiary().update({id: vm.beneficiary.id}, data).$promise.then(function () { 48 | $mdToast.show( 49 | $mdToast.simple() 50 | .textContent('Beneficiary Updated Successfully') 51 | .position('top right') 52 | ); 53 | }, function (resp) { 54 | var errors = ''; 55 | if(resp.data){ 56 | errors = resp.data.errors.map(function (data) { 57 | return data.defaultUserMessage; 58 | }); 59 | errors.join(' '); 60 | } 61 | $mdToast.show( 62 | $mdToast.simple() 63 | .textContent('Error in Adding Beneficiary: ' + errors) 64 | .position('top right') 65 | ); 66 | 67 | }); 68 | } 69 | } 70 | })(); -------------------------------------------------------------------------------- /app/src/transfers/transfers.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | {{ 'label.heading.transfers' | translate }} 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | {{ toAccountOption.accountNo }} ({{toAccountOption.accountType.value}}) 16 | 17 | 18 | 19 | 20 | 21 | {{ fromAccountOption.accountNo }} ({{fromAccountOption.accountType.value}}) 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 | 32 |
33 | 34 | 35 | 36 | 37 |
38 | {{ 'label.btn.cancel' | translate }} 39 | {{ 'label.btn.reviewTransfer' | translate }} 40 |
41 | 42 |
43 |
44 |
45 |
-------------------------------------------------------------------------------- /app/src/authentication/login/login.component.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('LoginCtrl', ['$scope', '$rootScope', '$state', '$mdToast', 'AUTH_EVENTS', 'AuthService', 'AccountService', LoginCtrl]); 6 | 7 | function LoginCtrl($scope, $rootScope, $state, $mdToast, AUTH_EVENTS, AuthService, AccountService) { 8 | 9 | var vm = this; 10 | vm.authenticating = false; 11 | 12 | /** 13 | * @method doLogin 14 | * @description To perform the login action on the page 15 | */ 16 | $scope.doLogin = function () { 17 | vm.authenticating = true; 18 | AuthService.doLogin().save($scope.loginData).$promise 19 | .then(function (result) { 20 | AuthService.setUser(result); 21 | AccountService.getClients().get().$promise 22 | .then(function (res) { 23 | vm.authenticating = false; 24 | $state.go("app.dashboard"); 25 | if (res.pageItems.length !== 0) { 26 | AccountService.setClientId(res.pageItems[0].id); 27 | $mdToast.show( 28 | $mdToast.simple() 29 | .content("Successful Login") 30 | .hideDelay(2000) 31 | .position('top right') 32 | ); 33 | 34 | } else { 35 | $mdToast.show( 36 | $mdToast.simple() 37 | .content("No Clients Found") 38 | .hideDelay(2000) 39 | .position('top right') 40 | ); 41 | AuthService.logout(); 42 | } 43 | }) 44 | .catch(function () { 45 | vm.authenticating = false; 46 | $mdToast.show( 47 | $mdToast.simple() 48 | .content("Not a Self Service User") 49 | .hideDelay(2000) 50 | .position('top right') 51 | ); 52 | AuthService.logout(); 53 | }) 54 | }).catch(function () { 55 | vm.authenticating = false; 56 | $mdToast.show( 57 | $mdToast.simple() 58 | .content("Invalid Login Credentials") 59 | .hideDelay(2000) 60 | .position('top right') 61 | ); 62 | }) 63 | } 64 | 65 | } 66 | 67 | })(); 68 | -------------------------------------------------------------------------------- /app/src/common/main.filters.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .filter('DateFormat', function (dateFilter) { 6 | return function (input) { 7 | if (input) { 8 | var tDate = new Date(input); 9 | return dateFilter(tDate, 'dd MMMM yyyy');//@todo Add this format to localstorage 10 | } 11 | return ''; 12 | }; 13 | }) 14 | .filter('StatusLookup', function () { 15 | return function (input) { 16 | var cssClassNameLookup = { 17 | "true": "statusactive", 18 | "false": "statusdeleted", 19 | "Active": "statusactive", 20 | "loanStatusType.submitted.and.pending.approval": "statuspending", 21 | "loanStatusType.approved": "statusApproved", 22 | "loanStatusType.active": "statusactive", 23 | "loanStatusType.overpaid": "statusoverpaid", 24 | "savingsAccountStatusType.submitted.and.pending.approval": "statuspending", 25 | "savingsAccountStatusType.approved": "statusApproved", 26 | "savingsAccountStatusType.active": "statusactive", 27 | "savingsAccountStatusType.activeInactive": "statusactiveoverdue", 28 | "savingsAccountStatusType.activeDormant": "statusactiveoverdue", 29 | "savingsAccountStatusType.matured": "statusmatured", 30 | "loanProduct.active": "statusactive", 31 | "clientStatusType.pending": "statuspending", 32 | "clientStatusType.closed":"statusclosed", 33 | "clientStatusType.rejected":"statusrejected", 34 | "clientStatusType.withdraw":"statuswithdraw", 35 | "clientStatusType.active": "statusactive", 36 | "clientStatusType.submitted.and.pending.approval": "statuspending", 37 | "clientStatusTYpe.approved": "statusApproved", 38 | "clientStatusType.transfer.in.progress": "statustransferprogress", 39 | "clientStatusType.transfer.on.hold": "statustransferonhold", 40 | "groupingStatusType.active": "statusactive", 41 | "groupingStatusType.pending": "statuspending", 42 | "groupingStatusType.submitted.and.pending.approval": "statuspending", 43 | "groupingStatusType.approved": "statusApproved", 44 | "shareAccountStatusType.submitted.and.pending.approval": "statuspending", 45 | "shareAccountStatusType.approved": "statusApproved", 46 | "shareAccountStatusType.active": "statusactive", 47 | "shareAccountStatusType.rejected": "statusrejected", 48 | "purchasedSharesStatusType.applied": "statuspending", 49 | "purchasedSharesStatusType.approved": "statusApproved", 50 | "purchasedSharesStatusType.rejected": "statusrejected" 51 | } 52 | 53 | return cssClassNameLookup[input]; 54 | } 55 | }) 56 | 57 | })(); 58 | 59 | -------------------------------------------------------------------------------- /app/app.config.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | //IS thsichaneg hknjseff 4 | angular.module('selfService') 5 | .config(function ($mdThemingProvider, $mdIconProvider, $httpProvider, $translateProvider, TENANT_IDENTIFIER) { 6 | 7 | $mdThemingProvider 8 | .theme('default') 9 | .primaryPalette('blue', { 10 | 'default': '600' 11 | }) 12 | .accentPalette('pink', { 13 | 'default': '500' 14 | }) 15 | .warnPalette('defaultPrimary'); 16 | 17 | $mdThemingProvider 18 | .theme('dark', 'default') 19 | .primaryPalette('defaultPrimary') 20 | .dark(); 21 | 22 | $mdThemingProvider 23 | .theme('grey', 'default') 24 | .primaryPalette('grey'); 25 | 26 | $mdThemingProvider 27 | .theme('custom', 'default') 28 | .primaryPalette('defaultPrimary', { 29 | 'hue-1': '50' 30 | }); 31 | 32 | $mdThemingProvider 33 | .definePalette('defaultPrimary', { 34 | '50': '#FFFFFF', 35 | '100': 'rgb(255, 198, 197)', 36 | '200': '#E75753', 37 | '300': '#E75753', 38 | '400': '#E75753', 39 | '500': '#E75753', 40 | '600': '#E75753', 41 | '700': '#E75753', 42 | '800': '#E75753', 43 | '900': '#E75753', 44 | 'A100': '#E75753', 45 | 'A200': '#E75753', 46 | 'A400': '#E75753', 47 | 'A700': '#E75753' 48 | }); 49 | 50 | $mdIconProvider 51 | .icon('user', 'assets/images/user.svg', 64); 52 | 53 | $httpProvider.defaults.useXDomain = true; 54 | //Set headers 55 | $httpProvider.defaults.headers.common['Content-Type'] = 'application/json; charset=utf-8'; 56 | // Mifos set Tenant 57 | $httpProvider.defaults.headers.common['Fineract-Platform-TenantId'] = TENANT_IDENTIFIER; 58 | $httpProvider.interceptors.push('APIRequestInterceptor'); 59 | 60 | var defaultLocale = 'en'; 61 | $translateProvider 62 | .useStaticFilesLoader({ 63 | prefix: 'global-translations/locale-', 64 | suffix: '.json' 65 | }) 66 | .useLocalStorage() 67 | .useSanitizeValueStrategy('escape') 68 | .preferredLanguage(defaultLocale) 69 | .fallbackLanguage(defaultLocale); 70 | } 71 | ) 72 | 73 | .run(['$rootScope', '$location', 'AuthService', function($rootScope, $location, AuthService) { 74 | $rootScope.$on('$locationChangeStart', function (event) { 75 | // redirect to login page if not logged in and trying to access a restricted page 76 | var restrictedPage = $.inArray($location.path(), ['/login', '/forgot', '/register', '/verify']) === -1; 77 | var loggedIn = AuthService.isAuthenticated(); 78 | if (restrictedPage) { 79 | if(!loggedIn) { 80 | $location.path('/login'); 81 | } 82 | } 83 | else if(loggedIn) { 84 | event.preventDefault(); 85 | } 86 | }); 87 | }]) 88 | 89 | })(); 90 | -------------------------------------------------------------------------------- /gulp/build.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var paths = gulp.paths; 6 | 7 | var $ = require('gulp-load-plugins')({ 8 | pattern: ['gulp-*', 'main-bower-files', 'uglify-save-license', 'del'] 9 | }); 10 | var hash = require('gulp-hash-filename'); 11 | 12 | var wiredep = require('wiredep').stream; 13 | var runSequence = require('run-sequence'); 14 | 15 | gulp.task('partials', function () { 16 | return gulp.src([ 17 | paths.src + '/src/**/*.html', 18 | paths.tmp + '/src/**/*.html' 19 | ]) 20 | .pipe($.minifyHtml({ 21 | empty: true, 22 | spare: true, 23 | quotes: true 24 | })) 25 | .pipe($.angularTemplatecache('templateCacheHtml.js', { 26 | module: 'selfService', 27 | root: 'src/' 28 | })) 29 | .pipe(hash({ 30 | "format": "{name}.{hash:8}{ext}" 31 | })) 32 | .pipe(gulp.dest(paths.dist + '/js')) 33 | }); 34 | 35 | gulp.task('html', ['partials'], function () { 36 | 37 | return gulp.src(paths.src + '/*.html') 38 | .pipe($.minifyHtml({ 39 | empty: true, 40 | spare: true, 41 | quotes: true 42 | })) 43 | .pipe(gulp.dest(paths.dist + '/')) 44 | .pipe($.size({title: paths.dist + '/', showFiles: true})); 45 | }); 46 | 47 | gulp.task('vendor', function () { 48 | var jsFilter = $.filter('**/*.js'); 49 | var cssFilter = $.filter('**/*.css'); 50 | 51 | return gulp.src($.mainBowerFiles()) 52 | .pipe(jsFilter) 53 | .pipe($.angularFilesort()) 54 | .pipe(gulp.dest(paths.dist + '/vendor')) 55 | .pipe(jsFilter.restore()) 56 | .pipe(cssFilter) 57 | .pipe(gulp.dest(paths.dist + '/vendor')) 58 | .pipe(cssFilter.restore()) 59 | }); 60 | 61 | gulp.task('app-js', function () { 62 | return gulp.src(paths.src + '/*.js') 63 | .pipe(gulp.dest(paths.dist)); 64 | }) 65 | 66 | gulp.task('js', ['vendor', 'partials', 'app-js'], function () { 67 | 68 | return gulp.src([ 69 | paths.src + '/src/**/*.js', 70 | '!' + paths.src + '/src/**/*.spec.js', 71 | '!' + paths.src + '/src/**/*.mock.js' 72 | ]) 73 | .pipe($.angularFilesort()) 74 | .pipe($.concat('app.js')) 75 | .pipe(hash({ 76 | "format": "{name}.{hash:8}{ext}" 77 | })) 78 | .pipe(gulp.dest(paths.dist + '/js')); 79 | }) 80 | 81 | gulp.task('images', function () { 82 | return gulp.src(paths.src + '/assets/images/**/*') 83 | .pipe(gulp.dest(paths.dist + '/assets/images/')); 84 | }); 85 | 86 | gulp.task('fonts', function () { 87 | return gulp.src($.mainBowerFiles()) 88 | .pipe($.filter('**/*.{eot,svg,ttf,woff}')) 89 | .pipe($.flatten()) 90 | .pipe(gulp.dest(paths.dist + '/fonts/')); 91 | }); 92 | 93 | gulp.task('misc', function () { 94 | return gulp.src([ 95 | paths.src + '/**/*.ico', 96 | paths.src + '/**/locale-*.json' 97 | ]) 98 | .pipe(gulp.dest(paths.dist + '/')); 99 | }); 100 | 101 | gulp.task('clean', function (done) { 102 | $.del([paths.dist + '/', paths.tmp + '/'], done); 103 | }); 104 | 105 | gulp.task('build', function (callback) { 106 | runSequence('clean', 107 | 'js', 'inject:build', 108 | 'images', 'fonts', 'misc', 109 | callback); 110 | }); 111 | -------------------------------------------------------------------------------- /app/src/loan-application/loan-application.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | {{ 'label.heading.applyloan' | translate }} 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | {{ productOption.name }} 16 | 17 | 18 |
19 | 20 | 21 | 22 | {{ loanPurpose.name }} 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
40 | 41 | 42 | 43 | 44 | 45 |
46 |
47 | {{ 'label.btn.cancel' | translate }} 48 | {{ 'label.btn.apply' | translate }} 49 |
50 | 51 |
52 |
53 |
54 |
-------------------------------------------------------------------------------- /app/src/shares-application/shares-application.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | {{ 'label.heading.applyshares' | translate }} 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | {{ productOption.name }} 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | {{ }} 31 | 32 | 33 |
34 | 35 | 36 | 37 | 38 |
39 | 40 | 41 | 42 | 43 |
44 | 45 | 46 | 47 | 48 | 49 |
50 |
51 | {{ 'label.btn.cancel' | translate }} 52 | {{ 'label.btn.apply' | translate }} 53 |
54 | 55 |
56 |
57 |
58 |
59 | 60 | -------------------------------------------------------------------------------- /app/src/transfers/transfers.component.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('AccountTransferCtrl', ['$scope', '$stateParams', '$filter', '$mdDialog', '$mdDateLocale', '$mdToast', 'AccountTransferService', AccountTransferCtrl]); 6 | 7 | /** 8 | * @module AccountTransferCtrl 9 | * @description 10 | * Account Transfer Controller 11 | */ 12 | function AccountTransferCtrl($scope, $stateParams, $filter, $mdDialog, $mdDateLocale, $mdToast, AccountTransferService) { 13 | 14 | var vm = this; 15 | vm.fromAccountOptions = []; 16 | vm.toAccountOptions = []; 17 | vm.transferFormData = getTransferFormDataObj() 18 | 19 | vm.disabledToAccount = false; 20 | vm.disabledfromAccount = false; 21 | 22 | vm.transferFormData = getTransferFormDataObj(); 23 | vm.getTransferTemplate = getTransferTemplate(); 24 | vm.clearForm = clearForm; 25 | vm.submit = submit; 26 | 27 | // FORMAT THE DATE FOR THE DATEPICKER 28 | $mdDateLocale.formatDate = function (date) { 29 | return $filter('date')(date, "dd-MM-yyyy"); 30 | }; 31 | 32 | function getTransferFormDataObj() { 33 | return { 34 | transferDate: new Date() 35 | }; 36 | } 37 | 38 | function getTransferTemplate() { 39 | AccountTransferService.getTransferTemplate().get(function (data) { 40 | vm.fromAccountOptions = data.fromAccountOptions; 41 | vm.toAccountOptions = data.toAccountOptions; 42 | 43 | if($stateParams.toAccount) { 44 | var i = 0; 45 | for(i=0; i < vm.toAccountOptions.length; i++) { 46 | if(vm.toAccountOptions[i].accountNo == $stateParams.toAccount.accountNo) { 47 | vm.transferFormData.toAccount = vm.toAccountOptions[i]; 48 | vm.disabledToAccount = true; 49 | break; 50 | } 51 | } 52 | } 53 | 54 | if($stateParams.fromAccount) { 55 | for(i=0; i < vm.fromAccountOptions.length; i++) { 56 | if(vm.fromAccountOptions[i].accountNo == $stateParams.fromAccount.accountNo) { 57 | vm.transferFormData.fromAccount = vm.fromAccountOptions[i]; 58 | vm.disabledfromAccount = true; 59 | break; 60 | } 61 | } 62 | } 63 | 64 | }); 65 | } 66 | 67 | function clearForm() { 68 | vm.transferFormData = getTransferFormDataObj(); 69 | $scope.transferForm.$setPristine(); 70 | $scope.transferForm.$setUntouched(); 71 | } 72 | 73 | function submit(ev) { 74 | $mdDialog.show({ 75 | controller: 'ReviewTransferDialogCtrl', 76 | controllerAs: 'vm', 77 | templateUrl: 'src/transfers/review-transfer-dialog/review-transfer-dialog.html', 78 | parent: angular.element(document.body), 79 | targetEvent: ev, 80 | locals: {transferFormData: vm.transferFormData}, 81 | clickOutsideToClose: true 82 | }).then(function (result) { 83 | if(result === "success"){ 84 | clearForm(); 85 | } 86 | }, function () { 87 | clearForm(); 88 | $mdToast.show( 89 | $mdToast.simple() 90 | .textContent('Transfer Cancelled') 91 | .position('top right') 92 | ); 93 | }); 94 | } 95 | 96 | 97 | } 98 | })(); -------------------------------------------------------------------------------- /app/src/loan-application/loan-application.component.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | angular.module('selfService') 5 | .controller('LoanApplicationCtrl', ['$scope', '$filter', '$mdToast', 'AccountService', 'LoanApplicationService', LoanApplicationCtrl]); 6 | 7 | /** 8 | * @module LoanApplicationCtrl 9 | * @description 10 | * Controls Application for Loan 11 | */ 12 | function LoanApplicationCtrl($scope, $filter, $mdToast, AccountService, LoanApplicationService) { 13 | var vm = this; 14 | 15 | vm.form = { 16 | locale: 'en_GB', 17 | dateFormat: 'dd MMMM yyyy', 18 | loanType: 'individual' 19 | }; 20 | vm.template = {}; 21 | vm.clientId = null; 22 | 23 | vm.init = init; 24 | vm.getLoanTemplate = getLoanTemplate; 25 | vm.clearForm = clearForm; 26 | vm.submit = submit; 27 | 28 | init(); 29 | 30 | function init() { 31 | AccountService.getClientId().then(function (clientId) { 32 | vm.clientId = clientId; 33 | getLoanTemplate(clientId, null); 34 | }); 35 | } 36 | 37 | function getLoanTemplate(clientId, productId) { 38 | LoanApplicationService.template().get({ 39 | templateType: 'individual', 40 | clientId: clientId, 41 | productId: productId 42 | }).$promise.then(function(template) { 43 | vm.template = template; 44 | vm.form.principal = vm.template.principal; 45 | vm.form.submittedOnDate = $filter('date','dd MMMM yyyy')(new Date(), 'dd MMMM yyyy'); 46 | vm.form.expectedDisbursementDate = $filter('date')(new Date(), 'dd MMMM yyyy'); 47 | }); 48 | } 49 | 50 | function clearForm() { 51 | $scope.loanApplicationForm.$setPristine(); 52 | $scope.loanApplicationForm.$setUntouched(); 53 | vm.template = {}; 54 | vm.form = { 55 | locale: 'en_GB', 56 | dateFormat: 'dd MMMM yyyy', 57 | loanType: 'individual' 58 | }; 59 | init(); 60 | } 61 | 62 | function submit() { 63 | var loanTemp = { 64 | clientId: vm.clientId, 65 | loanTermFrequency: vm.template.termFrequency, 66 | loanTermFrequencyType: vm.template.termPeriodFrequencyType.id, 67 | numberOfRepayments: vm.template.numberOfRepayments, 68 | repaymentEvery: vm.template.repaymentEvery, 69 | repaymentFrequencyType: vm.template.repaymentFrequencyType.id, 70 | interestRatePerPeriod: vm.template.interestRatePerPeriod, 71 | amortizationType: vm.template.amortizationType.id, 72 | interestType: vm.template.interestType.id, 73 | interestCalculationPeriodType: vm.template.interestCalculationPeriodType.id, 74 | transactionProcessingStrategyId: vm.template.transactionProcessingStrategyId 75 | }; 76 | var data = Object.assign({}, loanTemp, vm.form); 77 | LoanApplicationService.loan().save(data).$promise.then(function() { 78 | clearForm(); 79 | $mdToast.show( 80 | $mdToast.simple() 81 | .content("Loan Application Submitted Successfully") 82 | .hideDelay(2000) 83 | .position('top right') 84 | ); 85 | }, function(){ 86 | $mdToast.show( 87 | $mdToast.simple() 88 | .content("Error Creating Loan Application") 89 | .hideDelay(2000) 90 | .position('top right') 91 | ); 92 | }); 93 | } 94 | } 95 | })(); -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | We are glad that you here to contribute to the Online Banking App. Now, First things first, before you start contributing please do the following things: 2 | 3 | 1. Setup the developer environment. For that, you can refer the [README.md](https://github.com/openMF/web-self-service-app/blob/develop/README.md) or you can follow this [video](https://mifosforge.jira.com/wiki/spaces/docs/pages/498794497/Developer+Environment+Setup+for+Online+Banking+App+2.0). 4 | 2. Sign our [Mifos CLA](http://mifos.org/about-us/financial-legal/mifos-contributor-agreement/). 5 | 6 | After you are done with the previous steps, please follow these guidelines: 7 | 8 | ## Submitting an issue 9 | 10 | - Before submitting an issue please search the issue tracker whether that issue is already present or not. 11 | - Follow the issue template while creating the issue 12 | - Please include screenshots. 13 | - In case of feature addition please give a detailed description of the feature so, that we could help you in getting that feature successfully accepted into the project. 14 | - For UI enhancements please include mockups and workflows. 15 | 16 | ## Getting assigned to an issue 17 | - If you would like to work on an issue. please inform in the issue ticket by commenting on it ( you can comment like this eg: I would like to work on this issue) 18 | - Please reproduce the issue before commenting on the ticket. If you are not able to reproduce the issue please ask for clarification by commenting or ask the issue creator. 19 | - If any other contributor is already working on the issue, please ask the previous contributor whether he/she is still working on the issue. 20 | 21 | ## Coding guidelines 22 | - Please run `npm run lint` ( Eslint check whether the code is in the right format or not ) 23 | - Do not use inline statements for CSS changes. 24 | 25 | ## Submitting a Pull Request (PR) 26 | - If you are not at the develop branch them checkout to develop branch by 27 | 28 | ` git checkout develop` 29 | 30 | - Once, you are at develop branch then, before you start working on the fix or the feature , create a new branch using 31 | 32 | `git checkout -b ` 33 | 34 | Branch name eg: Fix #1234 - Issue Description 35 | ` 36 | - After you have done the changes, follows these steps to create a commit 37 | ` git add ` or ` git add -A ` 38 | 39 | ` git commit -m""` ( commit message : Fix #IssueNo. - brief description to make everyone understand what you have done) 40 | 41 | ` git push origin ` 42 | 43 | - If you have pushed the changes and want to do some changes to it after that 44 | 1. Go to the branch of the PR 45 | 2. Do the changes which you want to do. 46 | 3. Then `git add -A ` 47 | 4. ` git commit --amend` ( You can also change the commit name here ) 48 | 5. ` git push -f origin ` ( force push) 49 | 50 | - If you want to squash multiple commits then ( For example you want to squash last 2 commits on this branch to into one commit) 51 | 52 | `git rebase --interactive HEAD~2` 53 | 54 | `git push -f origin ` 55 | 56 | - Update your branch from the repository 57 | 58 | `git add upstream https://github.com/openMF/web-self-service-app.git` 59 | 60 | `git pull --rebase upstream develop` ( this will fetch from upstream and will rebase the branch too). 61 | 62 | ## Communication Channels 63 | - [Gitter channel](https://gitter.im/openMF/web-self-service-app) 64 | - [Mailing list](https://lists.sourceforge.net/lists/listinfo/mifos-developer) 65 | 66 | 67 | ## Important Points for new contributors: 68 | - Registration feature for a new user is only available in develop branch (for now). You can use these credentials `username: self-service password: password`. 69 | 70 | - These features are only UI ( because of unavailability of API for now), please do not create new issue specifying not working of these features. You are invited to do any UI modification to them, but please first ask before creating any UI modification issue. 71 | 1. Applying for new share and savings products. 72 | 2. Reports 73 | 3. About Us -------------------------------------------------------------------------------- /app/src/savings-application/savings-application.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | {{ 'label.heading.applysavings' | translate }} 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | {{ productOption.name }} 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | {{ }} 27 | 28 | 29 |
30 | 31 | 32 | 33 | {{ }} 34 | 35 | 36 |
37 | 38 | 39 | 40 | {{ }} 41 | 42 | 43 |
44 | 45 | 46 | 47 | {{ }} 48 | 49 | 50 |
51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 |
61 |
62 | {{ 'label.btn.cancel' | translate }} 63 | {{ 'label.btn.apply' | translate }} 64 |
65 | 66 |
67 |
68 |
69 |
70 | -------------------------------------------------------------------------------- /app/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page Not Found :( 6 | 141 | 142 | 143 |
144 |

Not found :(

145 |

Sorry, but the page you were trying to view does not exist.

146 |

It looks like this was the result of either:

147 |
    148 |
  • a mistyped address
  • 149 |
  • an out-of-date link
  • 150 |
151 | 154 | 155 |
156 | 157 | 158 | -------------------------------------------------------------------------------- /app/src/recent-transactions/recent-transactions.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | {{ 'label.heading.recentTransactions' | translate }} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | {{ 'label.msg.loadingRecentTransactions' | translate }}... 17 |
18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
{{ 'label.heading.id' | translate }}{{ 'label.heading.type' | translate }}{{ 'label.heading.officeName' | translate }}{{ 'label.heading.amount' | translate }}{{ 'label.heading.date' | translate }}
{{ transaction.id }}{{ transaction.type.value }}{{ transaction.officeName}}{{ transaction.currency.displaySymbol + ' ' + transaction.amount}}{{ transaction.date | DateFormat }}
41 |
42 |
43 | 46 |
47 |
48 |
49 |
50 | 51 |

{{ 'label.heading.recentTransactions' | translate }}

52 | 53 | 54 | 55 | 56 |
57 | 58 | 59 | 60 |
61 |
62 |
63 |

{{transaction.id}}

64 |
65 |

Type:  

66 |

{{ transaction.type.value }}

67 |
68 |
69 |

Office Name:  

70 |

{{ transaction.officeName}}

71 |
72 |
73 |

Amount:  

74 |

{{ transaction.currency.displaySymbol + ' ' + transaction.amount}}

75 |
76 |
77 |

Date:  

78 |

{{ transaction.date | DateFormat }}

79 |
80 |
81 | 82 | 83 |
84 | 85 |
86 | 87 |
88 |
89 |
90 |
91 | 94 |
95 | 96 |
97 | -------------------------------------------------------------------------------- /app/assets/stylesheets/_table.scss: -------------------------------------------------------------------------------- 1 | // This file based on http://codepen.io/zavoloklom/pen/IGkDz 2 | 3 | // VARIABLES 4 | $table-header-font-weight: 400; 5 | $table-header-font-color: #757575; 6 | 7 | $table-cell-padding: 1.2rem; 8 | 9 | $table-bg: #fff; 10 | $table-bg-accent: #f5f5f5; 11 | $table-bg-hover: rgba(0,0,0,.12); 12 | $table-bg-active: $table-bg-hover; 13 | $table-border-color: #e0e0e0; 14 | 15 | 16 | // MIXINS 17 | @mixin transition($transition-property, $transition-time, $method) { 18 | -webkit-transition: $transition-property $transition-time $method; 19 | -moz-transition: $transition-property $transition-time $method; 20 | -ms-transition: $transition-property $transition-time $method; 21 | -o-transition: $transition-property $transition-time $method; 22 | transition: $transition-property $transition-time $method; 23 | } 24 | 25 | 26 | //TABLES 27 | .table { 28 | border-spacing: 0; 29 | width: 100%; 30 | max-width: 100%; 31 | margin-bottom: 2rem; 32 | background-color: $table-bg; 33 | > thead, 34 | > tbody, 35 | > tfoot { 36 | > tr { 37 | @include transition(all, 0.3s, ease); 38 | > th, 39 | > td { 40 | text-align: left; 41 | padding: $table-cell-padding; 42 | vertical-align: top; 43 | border-top: 0; 44 | @include transition(all, 0.3s, ease); 45 | } 46 | } 47 | } 48 | > thead > tr > th { 49 | font-weight: $table-header-font-weight; 50 | color: $table-header-font-color; 51 | vertical-align: bottom; 52 | border-bottom: 1px solid rgba(0,0,0,.12); 53 | } 54 | > caption + thead, 55 | > colgroup + thead, 56 | > thead:first-child { 57 | > tr:first-child { 58 | > th, 59 | > td { 60 | border-top: 0; 61 | } 62 | } 63 | } 64 | > tbody + tbody { 65 | border-top: 1px solid rgba(0,0,0,.12); 66 | } 67 | 68 | // Nesting 69 | .table { 70 | background-color: $table-bg; 71 | } 72 | 73 | // Remove border 74 | .no-border { 75 | border: 0; 76 | } 77 | } 78 | 79 | // Bordered version 80 | // 81 | // Add horizontal borders between columns. 82 | .table-bordered { 83 | border: 0; 84 | > thead, 85 | > tbody, 86 | > tfoot { 87 | > tr { 88 | > th, 89 | > td { 90 | border: 0; 91 | border-bottom: 1px solid $table-border-color; 92 | } 93 | } 94 | } 95 | > thead > tr { 96 | > th, 97 | > td { 98 | border-bottom-width: 2px; 99 | } 100 | } 101 | } 102 | 103 | 104 | // Hover effect 105 | // 106 | .table-hover { 107 | > tbody > tr:hover { 108 | > td, 109 | > th { 110 | background-color: $table-bg-hover; 111 | } 112 | } 113 | } 114 | 115 | // Responsive tables (vertical) 116 | // 117 | // Wrap your tables in `.table-responsive-vertical` and we'll make them mobile friendly 118 | // by vertical table-cell display. Only applies <768px. Everything above that will display normally. 119 | // For correct display you must add 'data-title' to each 'td' 120 | .table-responsive-vertical { 121 | 122 | @media screen and (max-width: 768px) { 123 | 124 | // Tighten up spacing 125 | > .table { 126 | margin-bottom: 0; 127 | background-color: transparent; 128 | > thead, 129 | > tfoot { 130 | display: none; 131 | } 132 | 133 | > tbody { 134 | display: block; 135 | 136 | > tr { 137 | display: block; 138 | border: 1px solid $table-border-color; 139 | border-radius: 2px; 140 | margin-bottom: $table-cell-padding; 141 | 142 | > td { 143 | background-color: $table-bg; 144 | display: block; 145 | vertical-align: middle; 146 | text-align: right; 147 | } 148 | > td[data-title]:before { 149 | content: attr(data-title); 150 | float: left; 151 | font-size: inherit; 152 | font-weight: $table-header-font-weight; 153 | color: $table-header-font-color; 154 | padding-right: 10px; 155 | } 156 | } 157 | } 158 | } 159 | 160 | // Special overrides for shadows 161 | &.shadow-z-1 { 162 | -webkit-box-shadow: none; 163 | -moz-box-shadow: none; 164 | box-shadow: none; 165 | > .table > tbody > tr { 166 | border: none; 167 | } 168 | } 169 | 170 | // Special overrides for the bordered tables 171 | > .table-bordered { 172 | border: 0; 173 | 174 | // Nuke the appropriate borders so that the parent can handle them 175 | > tbody { 176 | > tr { 177 | > td { 178 | border: 0; 179 | border-bottom: 1px solid $table-border-color; 180 | } 181 | > td:last-child { 182 | border-bottom: 0; 183 | } 184 | } 185 | } 186 | } 187 | 188 | // Special overrides for the striped tables 189 | > .table-striped { 190 | > tbody > tr > td, 191 | > tbody > tr:nth-child(odd) { 192 | background-color: $table-bg; 193 | } 194 | > tbody > tr > td:nth-child(odd) { 195 | background-color: $table-bg-accent; 196 | } 197 | } 198 | 199 | // Special overrides for hover tables 200 | > .table-hover { 201 | > tbody { 202 | > tr:hover > td, 203 | > tr:hover { 204 | background-color: $table-bg; 205 | } 206 | > tr > td:hover { 207 | background-color: $table-bg-hover; 208 | } 209 | } 210 | } 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /app/src/authentication/register/register.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 7 | 8 |
Create an account
9 | 10 |
11 | 12 | 14 |
15 |
16 | Account Number field is required 17 |
18 |
19 |
20 | 21 | 23 |
24 |
25 | Username field is required 26 |
27 |
28 |
29 | 30 |
31 | 32 | 34 |
35 |
36 | First Name field is required 37 |
38 |
39 |
40 | 41 | 43 |
44 |
45 | Last Name field is required 46 |
47 |
48 |
49 |
50 | 51 | 52 | 54 |
55 |
56 | Email field is required 57 |
58 |
59 | Email must be a valid e-mail address 60 |
61 |
62 |
63 | 64 | 65 | 66 | 67 | 68 | 69 | 71 |
72 |
73 | Password field is required 74 |
75 |
76 |
77 | 78 | 79 | 82 |
83 |
84 | Password (Confirm) field is required 85 |
86 |
87 |
88 | 89 |
90 | 91 |
92 | I read and accept 93 | terms and conditions 94 |
95 |
96 | 97 | 99 | CREATE MY ACCOUNT 100 | 101 |
102 | 103 | 107 |
108 |
109 |
-------------------------------------------------------------------------------- /app/global-translations/locale-en.json: -------------------------------------------------------------------------------- 1 | { 2 | "login.heading.logintoyouraccount" : "Login to your account", 3 | "login.btn.login": "Login", 4 | "login.btn.forgot": "Forgot Password", 5 | "login.btn.register": "New User? Create an Account", 6 | 7 | "nav.msg.welcome": "Welcome,", 8 | "nav.label.dashboard": "Dashboard", 9 | "nav.label.accounts": "Accounts", 10 | "nav.label.recenttransactions": "Recent Transactions", 11 | "nav.label.charges": "Charges", 12 | "nav.label.transfers": "Transfers", 13 | "nav.label.tpttransfers": "Third Party Transfers", 14 | "nav.label.beneficiaries": "Beneficiaries", 15 | "nav.label.aboutus": "About us", 16 | "nav.label.help": "Help", 17 | "nav.label.applyloan": "Apply For Loan", 18 | "nav.label.reports": "Reports", 19 | "nav.label.applysavings": "Apply For Savings", 20 | "nav.label.applyshares": "Apply For Shares", 21 | 22 | "label.heading.loans": "Loans", 23 | "label.heading.loanAccountList": "Loan Account List", 24 | "label.heading.status": "Status", 25 | "label.heading.accountNo": "Account #", 26 | "label.heading.loanAccount": "Loan Account", 27 | "label.heading.originalLoan": "Original Loan", 28 | "label.heading.loanBalance": "Loan Balance", 29 | "label.heading.amountPaid": "Amount Paid", 30 | "label.heading.type": "Type", 31 | "label.heading.savings": "Savings", 32 | "label.heading.savingAccountList": "Savings Account List", 33 | "label.heading.account": "Account", 34 | "label.heading.accountType": "Account Type", 35 | "label.heading.accountBalance": "Account Balance", 36 | "label.heading.shares": "Shares", 37 | "label.heading.shareAccountList": "Shares Account List", 38 | "label.heading.approvedShares": "Approved Shares", 39 | "label.heading.pendingShares": "Shares Pending Approval", 40 | "label.heading.charges": "Charges", 41 | "label.heading.name": "Name", 42 | "label.heading.dueAsOf": "Due As Of", 43 | "label.heading.due": "Due", 44 | "label.heading.paid": "Paid", 45 | "label.heading.waived": "Waived", 46 | "label.heading.outstanding": "Outstanding", 47 | "label.heading.recentTransactions": "Recent Transactions", 48 | "label.heading.id": "Id", 49 | "label.heading.officeName": "Office Name", 50 | "label.heading.amount": "Amount", 51 | "label.heading.date": "Date", 52 | "label.heading.transfers": "Transfers", 53 | "label.heading.beneficiariesList": "Beneficiaries List", 54 | "label.heading.clientName": "Client Name", 55 | "label.heading.transferLimit": "Transfer Limit", 56 | "label.heading.addbeneficiaries": "Add Beneficiary", 57 | "label.heading.actions": "Actions", 58 | "label.heading.editbeneficiaries": "Edit Beneficiary", 59 | "label.heading.accountId": "Account Id", 60 | "label.heading.currency": "Currency", 61 | "label.heading.balance": "Balance", 62 | "label.heading.totalAccounts": "Total Accounts", 63 | "label.heading.savingsAccounts": "Savings Accounts", 64 | "label.heading.shareAccounts": "Share Accounts", 65 | "label.heading.totalSavings": "Total Savings", 66 | "label.heading.totalLoan": "Total Loan", 67 | "label.heading.loanAccountOverview": "Loan Account Overview", 68 | "label.heading.savingsAccountOverview": "Savings Account Overview", 69 | "label.heading.shareAccountOverview": "Share Account Overview", 70 | "label.heading.applyloan": "Apply For Loan", 71 | "label.heading.applysavings": "Apply For Savings", 72 | "label.heading.applyshares": "Apply For Shares", 73 | "label.heading.outstanding": "Outstanding Balance", 74 | "label.heading.accountId": "Account Id", 75 | "label.heading.currency": "Currency", 76 | "label.heading.tpt": "Third Party Transfers", 77 | "label.heading.transactionhistoryGraph": "Graph for transaction history", 78 | "label.heading.category": "Category", 79 | "label.headping.reports": "Reports", 80 | "label.heading.aboutUs": "About Us", 81 | 82 | "label.msg.loadingCharges": "Loading Charges", 83 | "label.msg.loadingRecentTransactions": "Loading Recent Transactions", 84 | "label.msg.loadingBeneficiaries": "Loading Beneficiaries", 85 | "label.msg.logginIn": "Logging In", 86 | 87 | "label.input.search": "Search", 88 | "label.input.payTo": "Pay To", 89 | "label.input.payFrom": "Pay From", 90 | "label.input.amount": "Amount", 91 | "label.input.transferDate": "Transfer Date", 92 | "label.input.remark": "Remark", 93 | "label.input.beneficiaryName": "Beneficiary Name", 94 | "label.input.officeName": "Office Name", 95 | "label.input.accountNumber": "Account Number", 96 | "label.input.transferLimit": "Transfer Limit", 97 | "label.input.accountType": "Account Type", 98 | "label.input.loanproductOptions": "Loan Product Options", 99 | "label.input.savingsproductOptions": "Savings Product Options", 100 | "label.input.sharesproductOptions": "Shares Product Options", 101 | "label.input.purposeOfLoan": "Purpose Of Loan", 102 | "label.input.currency": "Currency", 103 | "label.input.principal": "Principal", 104 | "label.input.submittedOn": "Submitted On", 105 | "label.input.expectedDisbursementDate": "Expected Disbursement Date", 106 | "label.input.accountno": "Account Number", 107 | "label.input.accountType" : "Account Type", 108 | "label.input.repaymentType": "Repayment Type", 109 | "label.input.transactionType": "Transaction Type", 110 | "label.input.numberOfShares": "Number of Shares", 111 | "label.input.todaysPrice": "Today's Price", 112 | "label.input.defaultSavingsAccount": "Default Savings Account", 113 | "label.input.applicationDate": "Application Date", 114 | "label.input.nominalAnnualInterest": "Nominal Annual Interest", 115 | "label.input.interestCompoundingPeriod": "Interest Compounding Period", 116 | "label.input.interestPostingPeriod": "Interest Posting Period", 117 | "label.input.interestCalculatedUsing": "Interest Calculated Using", 118 | "label.input.daysInYear": "Days In Year", 119 | 120 | "label.btn.cancel": "Cancel", 121 | "label.btn.reviewTransfer": "Review Transfer", 122 | "label.btn.reviewBeneficiary": "Review Beneficiary", 123 | "label.btn.editBeneficiary": "Edit Beneficiary", 124 | "label.btn.deposit": "Deposit", 125 | "label.btn.makepayment": "Make Payment", 126 | "label.btn.transfer": "Transfer", 127 | "label.btn.apply": "Apply" 128 | } -------------------------------------------------------------------------------- /app/src/charges/charges.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | {{ 'label.heading.charges' | translate }} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | {{ 'label.msg.loadingCharges' | translate }}... 17 |
18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
{{ 'label.heading.status' | translate }}{{ 'label.heading.name' | translate }}{{ 'label.heading.dueAsOf' | translate }}{{ 'label.heading.due' | translate }}{{ 'label.heading.paid' | translate }}{{ 'label.heading.waived' | translate }}{{ 'label.heading.outstanding' | translate }}
{{charge.name}}{{charge.dueDate | DateFormat}}{{charge.currency.displaySymbol + ' ' + (charge.amount | number)}}{{charge.currency.displaySymbol + ' ' + (charge.amountPaid | number)}}{{charge.currency.displaySymbol + ' ' + (charge.amountWaived | number)}}{{charge.currency.displaySymbol + ' ' + (charge.amountOutstanding | number)}}
45 |
46 |
47 | 50 |
51 |
52 |
53 |
54 | 55 |
56 |

{{ 'label.heading.charges' | translate }}

57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 |
65 |
66 |
67 |
68 | 69 |
70 |

71 |

{{charge.name}}

72 |
73 |

Due As of: 

74 |

{{charge.dueDate | DateFormat}}

75 |
76 |
77 |

Due: 

78 |

{{charge.currency.displaySymbol + ' ' + (charge.amount | number)}}

79 |
80 |
81 |

Paid: 

82 |

{{charge.currency.displaySymbol + ' ' + (charge.amountPaid | number)}}

83 |
84 |
85 |

Waived: 

86 |

{{charge.currency.displaySymbol + ' ' + (charge.amountWaived | number)}}

87 |
88 |
89 |

Outstanding: 

90 |

{{charge.currency.displaySymbol + ' ' + (charge.amountOutstanding | number)}}

91 |
92 |
93 | 94 | 95 |
96 | 97 |
98 | 99 |
100 |
101 |
102 |
103 | 106 |
107 |
-------------------------------------------------------------------------------- /app/src/dashboard/dashboard.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 | 6 | {{ 'label.heading.totalAccounts' | translate }} 7 | 8 | 9 | 10 | 11 |

{{ vm.dashboardData.totalAccounts}}

12 |
13 |
14 | 15 | 16 | 17 | {{ 'label.heading.loanAccount' | translate }} 18 | 19 | 20 | 21 | 22 |

{{ vm.dashboardData.loanAccounts.length}}

23 |
24 |
25 | 26 | 27 | 28 | {{ 'label.heading.savingsAccounts' | translate }} 29 | 30 | 31 | 32 | 33 |

{{ vm.dashboardData.savingsAccounts.length}}

34 |
35 |
36 | 37 | 38 | 39 | {{ 'label.heading.shareAccounts' | translate }} 40 | 41 | 42 | 43 | 44 |

{{ vm.dashboardData.shareAccounts.length}}

45 |
46 |
47 |
48 |
49 | 50 |

{{ 'label.heading.totalAccounts' | translate }}

51 |

{{ vm.dashboardData.totalSavings }}

52 |
53 | 54 |

{{ 'label.heading.totalLoan' | translate }}

55 |

{{ vm.dashboardData.totalLoan }}

56 |
57 |
58 |
59 | 60 | 61 | {{ 'label.heading.loanAccountOverview' | translate }} 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | {{ 'label.heading.savingsAccountOverview' | translate }} 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | {{ 'label.heading.shareAccountOverview' | translate }} 80 | 81 | 82 | 83 | 84 | 85 | 86 |
87 |
88 | 89 | 90 | 91 | {{'label.heading.transactionhistoryGraph' | translate}} 92 | 93 | 94 | 95 |
96 |
97 |
98 | 99 | 100 | 101 | 102 |
103 |
104 | 105 | 106 | 107 | {{ accountType }} 108 | 109 | 110 |
111 |
112 | 113 | 114 | 115 | {{ paymentType }} 116 | 117 | 118 |
119 | 120 |
121 |
122 | Generate Graph 123 |
124 |
125 | 126 | 127 | {{vm.accountType}} 128 | 129 | 130 | 131 |

Sorry, Graphs for Shares are not available now...

132 |
133 |
134 | 135 |
136 |
137 |
138 |
139 | 140 | -------------------------------------------------------------------------------- /app/src/beneficiaries/beneficiaries-list/beneficiaries-list.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | {{ 'label.heading.beneficiariesList' | translate }} 6 | 7 | 8 | 9 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | {{ 'label.msg.loadingBeneficiaries' | translate }}... 18 |
19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 52 | 53 | 54 |
{{ 'label.heading.id' | translate }}{{ 'label.heading.accountNo' | translate }}{{ 'label.heading.accountType' | translate }}{{ 'label.heading.transferLimit' | translate }}{{ 'label.heading.name' | translate }}{{ 'label.heading.officeName' | translate }}{{ 'label.heading.clientName' | translate }}{{ 'label.heading.actions' | translate }}
{{ beneficiary.id }}{{ beneficiary.accountNumber }}{{ beneficiary.accountType.value }}{{ beneficiary.transferLimit }}{{ beneficiary.name }}{{ beneficiary.officeName }}{{ beneficiary.clientName }} 45 | 46 | edit 47 | 48 | 49 | delete 50 | 51 |
55 |
56 |
57 | 60 |
61 |
62 |
63 |
64 | 65 |
66 |

{{ 'label.heading.beneficiariesList' | translate }}

67 | 68 | 69 | 71 | 72 | 73 | 74 | 75 |
76 |
77 |
78 |

{{ beneficiary.id }}

79 |
80 |

Account#: 

81 |

{{ beneficiary.accountNumber }}

82 |
83 |
84 |

Account Type: 

85 |

{{ beneficiary.accountType.value }}

86 |
87 |
88 |

Transfer Limit: 

89 |

{{ beneficiary.transferLimit }}

90 |
91 |
92 |

Name: 

93 |

{{ beneficiary.name }}

94 |
95 |
96 |

Office Name: 

97 |

{{ beneficiary.officeName }}

98 |
99 |
100 |

Client Name: 

101 |

{{ beneficiary.clientName }}

102 |
103 |
104 |
105 | 106 | edit 107 | 108 | 109 | delete 110 | 111 |
112 | 113 | 114 |
115 | 116 |
117 | 118 |
119 |
120 |
121 |
122 | 125 |
126 |
127 | 128 | 129 | 130 | add 131 | 132 | -------------------------------------------------------------------------------- /app/src/common/main.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 | 6 | 7 |

{{'nav.msg.welcome' | translate}} {{vm.profile.displayName}}

8 |
9 |
10 |
11 | 12 | 15 | 16 | 18 |
19 | home {{ 'nav.label.dashboard' | translate}} 20 |
21 |
22 | 23 | 25 |
26 | account_balance_wallet {{ 'nav.label.accounts' | translate}} 27 |
28 |
29 | 30 | 32 |
33 | trending_up {{ 'nav.label.recenttransactions' | translate}} 34 |
35 |
36 | 37 | 39 |
40 | attach_money {{ 'nav.label.charges' | translate }} 41 |
42 |
43 | 44 | 46 |
47 | attach_money {{ 'nav.label.transfers' | translate }} 48 |
49 |
50 | 51 | 53 |
54 | attach_money {{ 'nav.label.tpttransfers' | translate }} 55 |
56 |
57 | 58 | 60 |
61 | group {{ 'nav.label.beneficiaries' | translate }} 62 |
63 |
64 | 65 | 67 |
68 | ballot {{ 'nav.label.reports' | translate }} 69 |
70 |
71 | 72 | 74 |
75 | assignment {{ 'nav.label.applyloan' | translate }} 76 |
77 |
78 | 79 | 81 |
82 | assignment {{ 'nav.label.applysavings' | translate }} 83 |
84 |
85 | 86 | 88 |
89 | assignment {{ 'nav.label.applyshares' | translate }} 90 |
91 |
92 | 93 | 95 |
96 | info {{ 'nav.label.aboutus' | translate }} 97 |
98 |
99 | 100 | 102 |
103 | help {{ 'nav.label.help' | translate }} 104 |
105 |
106 |
107 |
108 | 109 |
110 | 111 | 112 | menu 113 | 114 |
115 | 116 | {{vm.userDetails.username}} 117 | 118 | 119 | 120 | 121 | 122 | 123 |
124 |

Profile

125 |
126 |
127 |
128 | 129 | 130 |
131 |

Logout

132 |
133 |
134 |
135 |
136 |
137 | 138 | 142 | 143 |
144 | 145 | 146 |
147 |
148 |
149 | --------------------------------------------------------------------------------