Merge tag 'v0.0.1-alpha.1'
This commit is contained in:
commit
091179f627
503 changed files with 28671 additions and 1651 deletions
58
.angular-cli.json
Normal file
58
.angular-cli.json
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
{
|
||||||
|
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||||
|
"project": {
|
||||||
|
"version": "1.0.0-alpha.4",
|
||||||
|
"name": "coreui-angular"
|
||||||
|
},
|
||||||
|
"apps": [
|
||||||
|
{
|
||||||
|
"root": "src",
|
||||||
|
"outDir": "dist",
|
||||||
|
"assets": ["assets"],
|
||||||
|
"index": "index.html",
|
||||||
|
"main": "main.ts",
|
||||||
|
"polyfills": "polyfills.ts",
|
||||||
|
"test": "test.ts",
|
||||||
|
"tsconfig": "tsconfig.app.json",
|
||||||
|
"testTsconfig": "tsconfig.spec.json",
|
||||||
|
"prefix": "app",
|
||||||
|
"scripts": [
|
||||||
|
"../node_modules/moment/min/moment.min.js"
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"scss/style.scss"
|
||||||
|
],
|
||||||
|
"environmentSource": "environments/environment.ts",
|
||||||
|
"environments": {
|
||||||
|
"dev": "environments/environment.ts",
|
||||||
|
"prod": "environments/environment.prod.ts",
|
||||||
|
"local": "environments/environment.local.ts"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"e2e": {
|
||||||
|
"protractor": {
|
||||||
|
"config": "./protractor.conf.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": [
|
||||||
|
{
|
||||||
|
"project": "src/tsconfig.app.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"project": "src/tsconfig.spec.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"project": "e2e/tsconfig.e2e.json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"test": {
|
||||||
|
"karma": {
|
||||||
|
"config": "./karma.conf.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaults": {
|
||||||
|
"styleExt": "scss",
|
||||||
|
"prefixInterfaces": false
|
||||||
|
}
|
||||||
|
}
|
14
.editorconfig
Normal file
14
.editorconfig
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# Editor configuration, see http://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
max_line_length = 0
|
||||||
|
trim_trailing_whitespace = false
|
27
.gitignore
vendored
27
.gitignore
vendored
|
@ -17,6 +17,33 @@ $RECYCLE.BIN/
|
||||||
# Windows shortcuts
|
# Windows shortcuts
|
||||||
*.lnk
|
*.lnk
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/bower_components
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
/.idea
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
|
||||||
|
# misc
|
||||||
|
/.sass-cache
|
||||||
|
/connect.lock
|
||||||
|
/coverage/*
|
||||||
|
/libpeerconnection.log
|
||||||
|
npm-debug.log
|
||||||
|
testem.log
|
||||||
|
/typings
|
||||||
|
|
||||||
|
# e2e
|
||||||
|
/e2e/*.js
|
||||||
|
/e2e/*.map
|
||||||
|
|
||||||
|
# local env variable
|
||||||
|
/src/environments/environment.local.ts
|
||||||
|
|
||||||
# =========================
|
# =========================
|
||||||
# Operating System Files
|
# Operating System Files
|
||||||
# =========================
|
# =========================
|
||||||
|
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016 creativeLabs Lukasz Holeczek.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the Software), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, andor sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
65
README.md
65
README.md
|
@ -1,2 +1,63 @@
|
||||||
# FoodLoop-Web
|
# LocalLoop Web Interface
|
||||||
For information on how to edit the CoreUI, see here: http://coreui.io/docs/getting-started/introduction
|
|
||||||
|
This is the repository for the LocalLoop web interface, for traders and
|
||||||
|
customers to see and submit data to the service.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
To get started with development, you will need an up to date version of
|
||||||
|
node.js, git, and access to either the backend dev server, or a local running
|
||||||
|
copy of the backend server from [LocalLoop Server][LocalLoop-Server].
|
||||||
|
|
||||||
|
For your local node.js, We reccomend using [n][tj/n] on \*nix and Mac, for
|
||||||
|
Windows take a look at [nodist][marcelklehr/nodist] - although other options
|
||||||
|
exist. We reccomend Node.js version 8.0.0+ and npm version 5.3.0+.
|
||||||
|
|
||||||
|
To get this repository set up, first clone it and then run the following
|
||||||
|
commands:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install -g @angular/cli
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
[LocalLoop-Server]:https://github.com/Pear-Trading/Foodloop-Server
|
||||||
|
[tj/n]:https://github.com/tj/n
|
||||||
|
[marcelklehr/nodist]:https://github.com/marcelklehr/nodist
|
||||||
|
|
||||||
|
## Environments
|
||||||
|
|
||||||
|
The app defaults to using the development server. For other options, see
|
||||||
|
`src/environments/environments.ts`
|
||||||
|
|
||||||
|
# Old README
|
||||||
|
|
||||||
|
This is the old README with some minor tips on getting started, and more reading.
|
||||||
|
|
||||||
|
## Angular2DevelopmentCLI
|
||||||
|
|
||||||
|
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.0.0-beta.32.3.
|
||||||
|
|
||||||
|
### Development server
|
||||||
|
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||||
|
|
||||||
|
### Code scaffolding
|
||||||
|
|
||||||
|
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive/pipe/service/class/module`.
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
|
||||||
|
|
||||||
|
### Running unit tests
|
||||||
|
|
||||||
|
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||||
|
|
||||||
|
### Running end-to-end tests
|
||||||
|
|
||||||
|
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||||
|
Before running the tests make sure you are serving the app via `ng serve`.
|
||||||
|
|
||||||
|
### Further help
|
||||||
|
|
||||||
|
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
||||||
|
|
149
app.js
149
app.js
|
@ -1,149 +0,0 @@
|
||||||
var app = angular.module(
|
|
||||||
"FoodLoop",
|
|
||||||
[
|
|
||||||
'ngRoute',
|
|
||||||
'ui.router'
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
// calling order
|
|
||||||
// 1-> app.config()
|
|
||||||
// 2-> app.run()
|
|
||||||
// 3-> directive's compile functions (if they are found in the dom)
|
|
||||||
// 4-> app.controller()
|
|
||||||
// 5-> directive's link functions (again, if found)
|
|
||||||
|
|
||||||
|
|
||||||
app.config(function($stateProvider, $urlRouterProvider) {
|
|
||||||
// use $urlRouterProvider to catch all the illeage cases
|
|
||||||
// $urlRouterProvider.otherwise("/login");
|
|
||||||
|
|
||||||
$stateProvider
|
|
||||||
// if loggin as user
|
|
||||||
.state('user',{
|
|
||||||
url:"/user",
|
|
||||||
views:{
|
|
||||||
'': {templateUrl:'pages/home/home.html',controller:'userCtrl'},
|
|
||||||
'header@user': {templateUrl:'pages/user/header.user.html'}, // nested view
|
|
||||||
'sidebar@user': {templateUrl:'pages/user/sidebar.user.html'},
|
|
||||||
'main@user': {templateUrl:'pages/user/main.user.html'},
|
|
||||||
},data:{
|
|
||||||
requireLogin: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.state('user.receipt',{
|
|
||||||
url:"",
|
|
||||||
views:{
|
|
||||||
'main@user': {templateUrl:'pages/receipt/receipt.html',controller:"receiptCtrl"},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.state('user.leaderboard',{
|
|
||||||
url:"",
|
|
||||||
views:{
|
|
||||||
'main@user': {templateUrl:'pages/user/main.leaderboard.html'},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.state('user.settings',{
|
|
||||||
url:"",
|
|
||||||
views:{
|
|
||||||
'main@user': {templateUrl:'pages/user/main.settings.html'},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.state('user.help',{
|
|
||||||
url:"",
|
|
||||||
views:{
|
|
||||||
'main@user': {templateUrl:'pages/user/main.settings.html'},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.state('admin.view_receipt',{
|
|
||||||
url:"",
|
|
||||||
params: {
|
|
||||||
receipt: null,
|
|
||||||
},
|
|
||||||
views:{
|
|
||||||
'main@admin': {
|
|
||||||
templateUrl:'pages/admin/main.receipt.html',
|
|
||||||
controller: function($scope,$stateParams){
|
|
||||||
$scope.receipt = $stateParams.receipt;
|
|
||||||
console.log($scope.receipt);
|
|
||||||
}},
|
|
||||||
},data:{
|
|
||||||
requireLogin: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.state('admin',{
|
|
||||||
url:"/admin",
|
|
||||||
controller: 'adminCtrl',
|
|
||||||
views:{
|
|
||||||
'': { templateUrl: 'pages/home/home.html',controller:'adminCtrl'}, // default view}
|
|
||||||
'header@admin': {templateUrl:'pages/admin/header.admin.html'}, // nested view
|
|
||||||
'sidebar@admin': {templateUrl:'pages/admin/sidebar.admin.html'},
|
|
||||||
'main@admin': {templateUrl:'pages/admin/main.admin.html'},
|
|
||||||
},data:{
|
|
||||||
requireLogin: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.state('trader',{
|
|
||||||
url:"/trader",
|
|
||||||
views:{
|
|
||||||
'': { templateUrl: 'pages/home/home.html',controller:'traderCtrl'}, // default view}
|
|
||||||
'header@trader': {templateUrl:'pages/trader/header.trader.html'}, // nested view
|
|
||||||
'sidebar@trader': {templateUrl:'pages/trader/sidebar.trader.html'},
|
|
||||||
'main@trader': {templateUrl:'pages/trader/main.trader.html'},
|
|
||||||
},data:{
|
|
||||||
requireLogin: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
.state('map',{
|
|
||||||
url: '/map',
|
|
||||||
templateUrl: 'pages/map/map.html',
|
|
||||||
controller: 'mapCtrl',
|
|
||||||
data: {
|
|
||||||
requireLogin : false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.state('login',{
|
|
||||||
url: '',
|
|
||||||
templateUrl: 'pages/login/login.html',
|
|
||||||
controller: 'loginCtrl',
|
|
||||||
data: {
|
|
||||||
requireLogin : false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
/* redirects to different page based on whether the user is login or not and */
|
|
||||||
/* if log on, check user type and redirect/construct a custom dashboard page */
|
|
||||||
/* to extend, users may have a custome dashboard with different layout, this */
|
|
||||||
/* needs to be handled using HTML page which is specifically constucted by */
|
|
||||||
/* page'controller and obtain variable setting from server */
|
|
||||||
// /* if not, redirect to login in page */
|
|
||||||
app.run(function ($rootScope,$state,authService) { // kickstart the application
|
|
||||||
// listening to the when a state change start
|
|
||||||
console.log("State changes");
|
|
||||||
$rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
|
|
||||||
console.log(toState);
|
|
||||||
// var requireLogin = toState.data.requireLogin;
|
|
||||||
// redirect to login page if satisfy the following conditions
|
|
||||||
// 1. seesion expired and user tries to access a page
|
|
||||||
// if ((requireLogin && typeof $rootScope.currentUser === 'undefined')) {
|
|
||||||
// event.preventDefault();
|
|
||||||
// $state.transitionTo('login');
|
|
||||||
// }
|
|
||||||
});
|
|
||||||
// Testing, configuration to firebase
|
|
||||||
var config = {
|
|
||||||
apiKey: "AIzaSyDypwjmMD818GQTTfyhTpx76ChJpDsZGek",
|
|
||||||
authDomain: "foodloop-666db.firebaseapp.com",
|
|
||||||
databaseURL: "https://foodloop-666db.firebaseio.com",
|
|
||||||
storageBucket: "foodloop-666db.appspot.com",
|
|
||||||
messagingSenderId: "832579459759"
|
|
||||||
};
|
|
||||||
firebase.initializeApp(config);
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
[0212/144844:ERROR:tcp_listen_socket.cc(76)] Could not bind socket to 127.0.0.1:6004
|
|
||||||
[0212/144844:ERROR:node_debugger.cc(86)] Cannot start debugger server
|
|
24
e2e/login.e2e-spec.ts
Normal file
24
e2e/login.e2e-spec.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import { LoginPageObject } from './login.po';
|
||||||
|
|
||||||
|
describe('Login Page', () => {
|
||||||
|
let page: LoginPageObject;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
page = new LoginPageObject();
|
||||||
|
page.navigateTo();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have a header saying login', () => {
|
||||||
|
expect(page.getLoginHeaderText()).toEqual('Login');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have a username box of type text', () => {
|
||||||
|
expect(page.isUsernameFieldPresent()).toBeTruthy();
|
||||||
|
expect(page.getUsernameFieldType()).toBe('text');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have a password box of type password', () => {
|
||||||
|
expect(page.isPasswordFieldPresent()).toBeTruthy();
|
||||||
|
expect(page.getPasswordFieldType()).toBe('password');
|
||||||
|
});
|
||||||
|
});
|
20
e2e/login.po.ts
Normal file
20
e2e/login.po.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import { browser, element, by } from 'protractor';
|
||||||
|
|
||||||
|
export class LoginPageObject {
|
||||||
|
navigateTo() {
|
||||||
|
return browser.get('/login');
|
||||||
|
}
|
||||||
|
|
||||||
|
getLoginHeaderText() {
|
||||||
|
return element(by.css('app-root h1')).getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
getUsernameField() { return element(by.id('username')); }
|
||||||
|
getPasswordField() { return element(by.id('password')); }
|
||||||
|
|
||||||
|
isUsernameFieldPresent() { return this.getUsernameField().isPresent(); }
|
||||||
|
isPasswordFieldPresent() { return this.getPasswordField().isPresent(); }
|
||||||
|
|
||||||
|
getUsernameFieldType() { return this.getUsernameField().getAttribute('type'); }
|
||||||
|
getPasswordFieldType() { return this.getPasswordField().getAttribute('type'); }
|
||||||
|
}
|
13
e2e/tsconfig.e2e.json
Normal file
13
e2e/tsconfig.e2e.json
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../out-tsc/e2e",
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es5",
|
||||||
|
"types": [
|
||||||
|
"jasmine",
|
||||||
|
"jasminewd2",
|
||||||
|
"node"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
75
index.html
75
index.html
|
@ -1,75 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html ng-app="FoodLoop" >
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
|
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
|
|
||||||
|
|
||||||
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-route.js"></script>
|
|
||||||
<head>
|
|
||||||
<title>FoodLoop Login</title>
|
|
||||||
|
|
||||||
<!-- Bootstrap and jQuery js -->
|
|
||||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
|
|
||||||
|
|
||||||
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n" crossorigin="anonymous"></script>
|
|
||||||
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb" crossorigin="anonymous"></script>
|
|
||||||
|
|
||||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"></script>
|
|
||||||
|
|
||||||
<script src="app.js"></script>
|
|
||||||
|
|
||||||
<!-- Include the ui-router script -->
|
|
||||||
<script src="//unpkg.com/angular-ui-router/release/angular-ui-router.min.js"></script>
|
|
||||||
|
|
||||||
<!-- D3 chart js -->
|
|
||||||
<script src="https://d3js.org/d3.v4.min.js"></script>
|
|
||||||
|
|
||||||
<!-- Map js dependecies -->
|
|
||||||
<script src="https://d3js.org/topojson.v2.min.js"></script>
|
|
||||||
|
|
||||||
<!-- Chart js -->
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.js"></script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- MVC for FoodLoop app -->
|
|
||||||
<script src="pages/login/loginCtrl.js"></script>
|
|
||||||
<!--<link rel="stylesheet" href="pages/login/login.css">-->
|
|
||||||
|
|
||||||
<script src="pages/home/homeCtrl.js"></script>
|
|
||||||
<link rel="stylesheet" href="pages/home/home.css">
|
|
||||||
|
|
||||||
<script src="pages/admin/adminCtrl.js"></script>
|
|
||||||
<!--<link rel="stylesheet" href="pages/admin/admin.css">-->
|
|
||||||
|
|
||||||
<script src="pages/receipt/receiptCtrl.js"></script>
|
|
||||||
<!--<link rel="stylesheet" href="pages/receipt/receipt.css">-->
|
|
||||||
|
|
||||||
<script src="pages/user/userCtrl.js"></script>
|
|
||||||
<!--<link rel="stylesheet" href="pages/user/user.css">-->
|
|
||||||
|
|
||||||
<script src="pages/trader/traderCtrl.js"></script>
|
|
||||||
<!--<link rel="stylesheet" href="pages/trader/trader.css">-->
|
|
||||||
|
|
||||||
<script src="pages/map/mapCtrl.js"></script>
|
|
||||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.3/dist/leaflet.css" />
|
|
||||||
<script src="https://unpkg.com/leaflet@1.0.3/dist/leaflet.js"></script>
|
|
||||||
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.33.0/mapbox-gl.js'></script>
|
|
||||||
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.33.0/mapbox-gl.css' rel='stylesheet' />
|
|
||||||
<!-- Import services-->
|
|
||||||
<script src="services/authService.js"></script>
|
|
||||||
<script src="services/chartService.js"></script>
|
|
||||||
<script src="services/uploadReceiptservice.js"></script>
|
|
||||||
|
|
||||||
<!-- firebase for testing -->
|
|
||||||
<script src="https://www.gstatic.com/firebasejs/3.6.9/firebase.js"></script>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body >
|
|
||||||
|
|
||||||
<!-- Dsiplay the main content -->
|
|
||||||
<ui-view></ui-view>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
44
karma.conf.js
Normal file
44
karma.conf.js
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
// Karma configuration file, see link for more information
|
||||||
|
// https://karma-runner.github.io/0.13/config/configuration-file.html
|
||||||
|
|
||||||
|
module.exports = function (config) {
|
||||||
|
config.set({
|
||||||
|
basePath: '',
|
||||||
|
frameworks: ['jasmine', '@angular/cli'],
|
||||||
|
plugins: [
|
||||||
|
require('karma-jasmine'),
|
||||||
|
require('karma-chrome-launcher'),
|
||||||
|
require('karma-jasmine-html-reporter'),
|
||||||
|
require('karma-coverage-istanbul-reporter'),
|
||||||
|
require('@angular/cli/plugins/karma')
|
||||||
|
],
|
||||||
|
client:{
|
||||||
|
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||||
|
},
|
||||||
|
files: [
|
||||||
|
{ pattern: './src/test.ts', watched: false }
|
||||||
|
],
|
||||||
|
preprocessors: {
|
||||||
|
'./src/test.ts': ['@angular/cli']
|
||||||
|
},
|
||||||
|
mime: {
|
||||||
|
'text/x-typescript': ['ts','tsx']
|
||||||
|
},
|
||||||
|
coverageIstanbulReporter: {
|
||||||
|
reports: [ 'html', 'lcovonly' ],
|
||||||
|
fixWebpackSourcePaths: true
|
||||||
|
},
|
||||||
|
angularCli: {
|
||||||
|
environment: 'dev'
|
||||||
|
},
|
||||||
|
reporters: config.angularCli && config.angularCli.codeCoverage
|
||||||
|
? ['progress', 'coverage-istanbul']
|
||||||
|
: ['progress', 'kjhtml'],
|
||||||
|
port: 9876,
|
||||||
|
colors: true,
|
||||||
|
logLevel: config.LOG_INFO,
|
||||||
|
autoWatch: true,
|
||||||
|
browsers: ['Chrome'],
|
||||||
|
singleRun: false
|
||||||
|
});
|
||||||
|
};
|
9984
package-lock.json
generated
Normal file
9984
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
63
package.json
Normal file
63
package.json
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
{
|
||||||
|
"name": "coreui-angular",
|
||||||
|
"version": "1.0.0-alpha.5",
|
||||||
|
"description": "Open Source Bootstrap Admin Template",
|
||||||
|
"author": "",
|
||||||
|
"url": "http://coreui.io",
|
||||||
|
"copyright": "Copyright 2017 creativeLabs Łukasz Holeczek",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"ng": "ng",
|
||||||
|
"start": "ng serve",
|
||||||
|
"build": "ng build",
|
||||||
|
"test": "ng test",
|
||||||
|
"lint": "ng lint",
|
||||||
|
"e2e": "ng e2e"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@angular/common": "4.0.3",
|
||||||
|
"@angular/compiler": "4.0.3",
|
||||||
|
"@angular/core": "4.0.3",
|
||||||
|
"@angular/forms": "4.0.3",
|
||||||
|
"@angular/http": "4.0.3",
|
||||||
|
"@angular/platform-browser": "4.0.3",
|
||||||
|
"@angular/platform-browser-dynamic": "4.0.3",
|
||||||
|
"@angular/router": "4.0.3",
|
||||||
|
"@angular/upgrade": "4.0.3",
|
||||||
|
"@types/moment": "^2.13.0",
|
||||||
|
"angular-in-memory-web-api": "^0.3.1",
|
||||||
|
"chart.js": "2.5.0",
|
||||||
|
"core-js": "2.4.1",
|
||||||
|
"moment": "^2.18.1",
|
||||||
|
"ng2-charts": "1.6.0",
|
||||||
|
"ng2-validation-manager": "^0.3.1",
|
||||||
|
"ngx-bootstrap": "1.6.6",
|
||||||
|
"ngx-pagination": "^3.0.1",
|
||||||
|
"rxjs": "5.4.2",
|
||||||
|
"ts-helpers": "1.1.2",
|
||||||
|
"webpack": "3.5.4",
|
||||||
|
"webpack-dev-server": "2.7.1",
|
||||||
|
"zone.js": "0.8.9"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@angular/cli": "1.3.0",
|
||||||
|
"@angular/compiler-cli": "4.0.3",
|
||||||
|
"@types/jasmine": "2.5.54",
|
||||||
|
"@types/jasminewd2": "2.0.2",
|
||||||
|
"@types/node": "8.0.24",
|
||||||
|
"codelyzer": "2.1.1",
|
||||||
|
"jasmine-core": "2.7.0",
|
||||||
|
"jasmine-spec-reporter": "4.2.1",
|
||||||
|
"karma": "1.7.0",
|
||||||
|
"karma-chrome-launcher": "2.2.0",
|
||||||
|
"karma-cli": "1.0.1",
|
||||||
|
"karma-coverage-istanbul-reporter": "1.3.0",
|
||||||
|
"karma-jasmine": "1.1.0",
|
||||||
|
"karma-jasmine-html-reporter": "0.2.2",
|
||||||
|
"protractor": "5.1.2",
|
||||||
|
"ts-node": "3.3.0",
|
||||||
|
"tslint": "4.5.1",
|
||||||
|
"typescript": "2.4.2"
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +0,0 @@
|
||||||
<div ui-view="header"></div>
|
|
||||||
<div ui-view="sidebar"></div>
|
|
||||||
<div ui-view="main"></div>
|
|
|
@ -1,67 +0,0 @@
|
||||||
/* this controller specifies the logic layer of the admin page */
|
|
||||||
/* including the content to be display, sidebar, header */
|
|
||||||
/* functionailities involve for an admin */
|
|
||||||
app.controller('adminCtrl', function($scope,$state) {
|
|
||||||
$scope.users;
|
|
||||||
$scope.controllby = "admin";
|
|
||||||
// Initialize Firebase
|
|
||||||
$scope.pending_receipt_sum = 2;
|
|
||||||
$scope.pending_receipt = [
|
|
||||||
{
|
|
||||||
receipt_ref: "r1",
|
|
||||||
submitted_by : "John Lemon",
|
|
||||||
submitted_time: "31",
|
|
||||||
submitted_amount: "8.66",
|
|
||||||
details: "sjadsjoiadsj iasdn aisdn alsdi jadi jasdi ajsdoi ndi snd"
|
|
||||||
}
|
|
||||||
,
|
|
||||||
{
|
|
||||||
submitted_by : "User007",
|
|
||||||
submitted_time: "21",
|
|
||||||
submitted_amount: "22.22"
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
/* section for receipt management start * /
|
|
||||||
/* review a pending receipt */
|
|
||||||
/* fetch a list of pending receipt from server */
|
|
||||||
/* fetch a list of approve receipt from server */
|
|
||||||
$scope.reviewReceipt = function(myReceipt){
|
|
||||||
// testing
|
|
||||||
console.log("[DEBUG]: reviewReceipt called");
|
|
||||||
// show page for review this receipt
|
|
||||||
$state.go('admin.view_receipt', {receipt: myReceipt})
|
|
||||||
//
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.approve_receipt = function(receipt_ref){
|
|
||||||
// call api to approve a pending receipt
|
|
||||||
// notify user
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$scope.fetch_pending_receipt = function(){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.fetch_submitted_receipt = function(){
|
|
||||||
|
|
||||||
}
|
|
||||||
/* section for receipt management end */
|
|
||||||
|
|
||||||
|
|
||||||
// Get a reference to the database service
|
|
||||||
var database = firebase.database();
|
|
||||||
firebase.database().ref('/users/').once('value').then(function(snapshot) {
|
|
||||||
$scope.users = snapshot.val();
|
|
||||||
});
|
|
||||||
|
|
||||||
$scope.test = function(){
|
|
||||||
|
|
||||||
console.log("CLiced ");
|
|
||||||
console.log($scope.users);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
<nav class="navbar navbar-toggleable-md fixed-top navbar-inverse" style="background-color:#0091EA;">
|
|
||||||
<button class="navbar-toggler navbar-toggler-right hidden-lg-up" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
|
|
||||||
<span class="navbar-toggler-icon"></span>
|
|
||||||
</button>
|
|
||||||
<a class="navbar-brand" href="#">FoodLoop</a>
|
|
||||||
|
|
||||||
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
|
|
||||||
<ul class="navbar-nav mr-auto">
|
|
||||||
<li class="nav-item active">
|
|
||||||
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Settings</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Profile</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Help</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<form class="form-inline mt-2 mt-md-0">
|
|
||||||
<input class="form-control mr-sm-2" type="text" placeholder="Search">
|
|
||||||
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
|
@ -1,50 +0,0 @@
|
||||||
<main class="col-sm-9 offset-sm-3 col-md-10 offset-md-2 pt-3">
|
|
||||||
|
|
||||||
<div class="row no-gutters">
|
|
||||||
<div class="col-2">
|
|
||||||
<div class="rankCard">
|
|
||||||
<div class="receiptCardHeader"> Section toolbox </div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<div class="receiptCard">
|
|
||||||
<div class="receiptCardHeader"> List/Table </div>
|
|
||||||
<div class="tableCard">
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Action</th>
|
|
||||||
<th>#</th>
|
|
||||||
<th>From</th>
|
|
||||||
<th>When</th>
|
|
||||||
<th>Amount</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr ng-repeat-start="receipt in pending_receipt">
|
|
||||||
<td>
|
|
||||||
<button type="button" class="btn btn-primary" ng-if="receipt.expanded" ng-click="receipt.expanded = false">review</button>
|
|
||||||
<button type="button" class="btn btn-primary" ng-if="!receipt.expanded" ng-click="receipt.expanded = true">review</button>
|
|
||||||
</td>
|
|
||||||
<td>{{$index + 1}}</td>
|
|
||||||
<td>{{receipt.submitted_by}}</td>
|
|
||||||
<td>{{receipt.submitted_time}} minutes ago</td>
|
|
||||||
<td>£{{receipt.submitted_amount}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr ng-if="receipt.expanded" ng-repeat-end="">
|
|
||||||
<td colspan="5">
|
|
||||||
<div class="receiptDetailCard">
|
|
||||||
{{receipt.details}}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- row first -->
|
|
||||||
|
|
||||||
</main>
|
|
|
@ -1,43 +0,0 @@
|
||||||
<main class="col-sm-9 offset-sm-3 col-md-10 offset-md-2 pt-3">
|
|
||||||
|
|
||||||
<div class="row no-gutters">
|
|
||||||
<div class="col-2">
|
|
||||||
<div class="rankCard">
|
|
||||||
<div class="receiptCardHeader"> Section toolbox </div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<div class="receiptCard">
|
|
||||||
<div class="receiptCardHeader">{{receipt.receipt_ref}}</div>
|
|
||||||
<div class="tableCard">
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>#</th>
|
|
||||||
<th>From</th>
|
|
||||||
<th>When</th>
|
|
||||||
<th>Amount</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>{{$index + 1}}</td>
|
|
||||||
<td>{{receipt.submitted_by}}</td>
|
|
||||||
<td>{{receipt.submitted_time}} minutes ago</td>
|
|
||||||
<td>£{{receipt.submitted_amount}}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<!-- table card-->
|
|
||||||
<div class="receiptImageCard">
|
|
||||||
<div> </div>
|
|
||||||
</div>
|
|
||||||
<!-- receiptImageCard-->
|
|
||||||
</div>
|
|
||||||
<!-- receipt card -->
|
|
||||||
</div>
|
|
||||||
<!-- col -->
|
|
||||||
</div>
|
|
||||||
<!-- row first -->
|
|
||||||
</main>
|
|
|
@ -1,46 +0,0 @@
|
||||||
<!-- This page defines a side bar for admin -->
|
|
||||||
<nav class="col-sm-3 col-md-2 hidden-xs-down bg-faded sidebar">
|
|
||||||
<ul class="nav nav-pills flex-column">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link active" href="#">Admin Portal <span class="sr-only">(current)</span></a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">User Management</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Trader Management</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Sign out</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul class="nav nav-pills flex-column" id="meq">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link active" href="#">Receipt Management</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Pending receipt
|
|
||||||
<span class="badge badge-danger">{{pending_receipt_sum}}</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Option 2</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Option 3</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul class="nav nav-pills flex-column">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Nav item again</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">One more nav</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Another nav item</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
|
@ -1,353 +0,0 @@
|
||||||
/*
|
|
||||||
* Base structure
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Move down content because we have a fixed navbar that is 50px tall */
|
|
||||||
body {
|
|
||||||
padding-top: 50px;
|
|
||||||
background-color: whitesmoke;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Typography
|
|
||||||
*/
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
padding-bottom: 9px;
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
}
|
|
||||||
|
|
||||||
main{
|
|
||||||
background-color: whitesmoke;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Sidebar
|
|
||||||
*/
|
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
position: fixed;
|
|
||||||
top: 51px;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: 1000;
|
|
||||||
padding: 20px;
|
|
||||||
overflow-x: hidden;
|
|
||||||
overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
|
|
||||||
border-right: 1px solid #eee;
|
|
||||||
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sidebar navigation */
|
|
||||||
.sidebar {
|
|
||||||
margin-top: -16px;
|
|
||||||
padding-left: 0;
|
|
||||||
padding-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-item {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-item + .nav-item {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-link {
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.profile-pic {
|
|
||||||
border-radius: 80%;
|
|
||||||
background-color: transparent;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: dodgerblue;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.profilePic{
|
|
||||||
padding: 16px;
|
|
||||||
background-color: transparent;
|
|
||||||
max-width: 100%;
|
|
||||||
height: 130px;
|
|
||||||
background-color: dodgerblue;
|
|
||||||
}
|
|
||||||
|
|
||||||
.profileInfo{
|
|
||||||
color:white;
|
|
||||||
padding: 16px;
|
|
||||||
padding-top: 30px;
|
|
||||||
height: 130px;
|
|
||||||
background-color: dodgerblue;
|
|
||||||
}
|
|
||||||
|
|
||||||
.profileTitle{
|
|
||||||
font-size: 0.8em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dashboard
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Placeholders */
|
|
||||||
.placeholders {
|
|
||||||
padding-bottom: 3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.placeholder img {
|
|
||||||
padding-top: 1.5rem;
|
|
||||||
padding-bottom: 1.5rem;
|
|
||||||
}
|
|
||||||
.title{
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
.flCard{
|
|
||||||
color:black;
|
|
||||||
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
|
|
||||||
transition: 0.3s;
|
|
||||||
border-radius: 3px;
|
|
||||||
font-size: 1em;
|
|
||||||
/*width: 100%;*/
|
|
||||||
height: 110px;;
|
|
||||||
margin-top: 16px;
|
|
||||||
background-color: white;
|
|
||||||
border: green;
|
|
||||||
padding:16px;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.rankCard{
|
|
||||||
color:black;
|
|
||||||
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
|
|
||||||
transition: 0.3s;
|
|
||||||
border-radius: 3px;
|
|
||||||
font-size: 1em;
|
|
||||||
height: 300px;;
|
|
||||||
margin-top: 16px;
|
|
||||||
background-color: white;
|
|
||||||
border: green;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.rankCardHeader{
|
|
||||||
border-radius: 3px 3px 0 0;
|
|
||||||
padding: 3px;
|
|
||||||
color:white;
|
|
||||||
height:30px;
|
|
||||||
background-color: dodgerblue;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chartCardHeader{
|
|
||||||
border-radius: 3px 3px 0 0;
|
|
||||||
padding: 3px;
|
|
||||||
color:white;
|
|
||||||
height:30px;
|
|
||||||
background-color: orangered;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rankCardContent{
|
|
||||||
padding: 3px;
|
|
||||||
/*color:white;*/
|
|
||||||
/*background-color: dodgerblue;*/
|
|
||||||
}
|
|
||||||
|
|
||||||
.flCardHeader{
|
|
||||||
height: 25px;
|
|
||||||
}
|
|
||||||
.flCardMain{
|
|
||||||
margin: -16px;
|
|
||||||
font-size: 3.0em;
|
|
||||||
color: dimgray;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chartCard{
|
|
||||||
color:black;
|
|
||||||
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
|
|
||||||
transition: 0.3s;
|
|
||||||
border-radius: 3px;
|
|
||||||
font-size: 1em;
|
|
||||||
height: 300px;;
|
|
||||||
margin-top: 16px;
|
|
||||||
background-color: white;
|
|
||||||
|
|
||||||
}
|
|
||||||
.flCardNote{
|
|
||||||
font-size: 0.8em;
|
|
||||||
color: dodgerblue;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
#receiptTable{
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* CSS FOR RECEIPT */
|
|
||||||
|
|
||||||
.receiptItem{
|
|
||||||
color:black;
|
|
||||||
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.2);
|
|
||||||
transition: 0.3s;
|
|
||||||
border-radius: 3px;
|
|
||||||
font-size: 1em;
|
|
||||||
padding: 16px;
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.receiptCard{
|
|
||||||
color:black;
|
|
||||||
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
|
|
||||||
transition: 0.3s;
|
|
||||||
border-radius: 3px;
|
|
||||||
font-size: 1em;
|
|
||||||
margin-top: 16px;
|
|
||||||
padding:16px;
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.receiptCardHeader{
|
|
||||||
border-radius: 3px 3px 0 0;
|
|
||||||
padding: 3px;
|
|
||||||
color:white;
|
|
||||||
padding: 16px;
|
|
||||||
background-color: dodgerblue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.receiptDetailCard{
|
|
||||||
color:black;
|
|
||||||
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.2);
|
|
||||||
transition: 0.3s;
|
|
||||||
border-radius: 3px;
|
|
||||||
font-size: 1em;
|
|
||||||
height: 300px;
|
|
||||||
margin-top: 16px;
|
|
||||||
background-color: lightcyan;
|
|
||||||
}
|
|
||||||
|
|
||||||
.addButton{
|
|
||||||
background-color: transparent;
|
|
||||||
font-size: 1.0em;
|
|
||||||
margin-left: 50%;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.dragImageBox:hover{
|
|
||||||
background-color: whitesmoke;
|
|
||||||
}
|
|
||||||
.dragImageBox{
|
|
||||||
border: 2px dashed dodgerblue;
|
|
||||||
border-radius: 4px;
|
|
||||||
background-color:white;
|
|
||||||
height: 150px;
|
|
||||||
transition: 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.thumb{
|
|
||||||
color:black;
|
|
||||||
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.2);
|
|
||||||
transition: 0.3s;
|
|
||||||
border-radius: 3px;
|
|
||||||
font-size: 1em;
|
|
||||||
background-color: white;
|
|
||||||
width: 50px;
|
|
||||||
height: 130px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TEMPALTE CSS FOR DISPLAY A CUSTOM CARD */
|
|
||||||
|
|
||||||
.pearCard{
|
|
||||||
color:black;
|
|
||||||
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.2);
|
|
||||||
transition: 0.3s;
|
|
||||||
border-radius: 3px;
|
|
||||||
font-size: 1em;
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* On mouse-over, add a deeper shadow */
|
|
||||||
.pearCard:hover {
|
|
||||||
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.pearCardFooter{
|
|
||||||
width: 100%;
|
|
||||||
margin-bottom: -16px;
|
|
||||||
background-color: lightcyan;
|
|
||||||
}
|
|
||||||
.pearAutoHeight{
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
.pearCardHeader{
|
|
||||||
border-radius: 3px 3px 0 0;
|
|
||||||
padding: 9px;
|
|
||||||
color:white;
|
|
||||||
background-color: dodgerblue;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pearOrange{
|
|
||||||
background-color: orangered;
|
|
||||||
}
|
|
||||||
.pearBlue{
|
|
||||||
background-color: dodgerblue;
|
|
||||||
}
|
|
||||||
.pearGreen{
|
|
||||||
background-color: lawngreen;
|
|
||||||
}
|
|
||||||
.pearYellow{
|
|
||||||
background-color: yellow;
|
|
||||||
}
|
|
||||||
.pearPurple{
|
|
||||||
background-color: purple;
|
|
||||||
}
|
|
||||||
|
|
||||||
.padding16{
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.margin16{
|
|
||||||
margin-top:16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* LOGIN CSS */
|
|
||||||
.mainSection{
|
|
||||||
margin-top: 20%;
|
|
||||||
padding:16px;
|
|
||||||
color:black;
|
|
||||||
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.2);
|
|
||||||
transition: 0.3s;
|
|
||||||
border-radius: 3px;
|
|
||||||
font-size: 1em;
|
|
||||||
/*height: 150px;*/
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mainItem{
|
|
||||||
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mainItem input[type=text] {
|
|
||||||
/*border: 2px solid ;*/
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mainItem input[type=password] {
|
|
||||||
/*border: 2px solid ;*/
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
<!-- ideally, this page would be the tempalte for all user types, admin -->
|
|
||||||
<!-- user, trader etc. this home page will defines the common html structure-->
|
|
||||||
<!-- among differnet user page -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- use ui-view to display header,sidebar and main content of differnet types -->
|
|
||||||
<!-- this would the common layout, header, siderbar, main -->
|
|
||||||
<!-- the actual content and logic within will be managed by -->
|
|
||||||
<!-- seperate controller,css, html files -->
|
|
||||||
|
|
||||||
<div ui-view="header"></div>
|
|
||||||
<div ui-view="sidebar"></div>
|
|
||||||
<div ui-view="main"></div>
|
|
|
@ -1,18 +0,0 @@
|
||||||
app.controller('homeCtrl', function($scope) {
|
|
||||||
|
|
||||||
// $stateProvider.state('contacts', {
|
|
||||||
// template: '<h1>My Contacts</h1>'
|
|
||||||
// }) $scope.username = "user";
|
|
||||||
$scope.controllby = "home";
|
|
||||||
|
|
||||||
// $rootScope.userType = "admin";
|
|
||||||
// $scope.getViewByUserType = function(){
|
|
||||||
// return {
|
|
||||||
// '': {templateUrl: 'pages/home/home.html',controller:'adminCtrl'}, // default view
|
|
||||||
// 'header@home-admin': {templateUrl:'pages/admin/header.admin.html'}, // nested view
|
|
||||||
// 'sidebar@home-admin': {templateUrl:'pages/admin/sidebar.admin.html'},
|
|
||||||
// 'main@home-admin': {templateUrl:'pages/admin/main.admin.html'},
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// $scope.header = "i m not a header";
|
|
||||||
});
|
|
|
@ -1,69 +0,0 @@
|
||||||
<nav class="navbar fixed-top navbar-light bg-faded">
|
|
||||||
|
|
||||||
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
|
|
||||||
<span class="navbar-toggler-icon"></span>
|
|
||||||
</button>
|
|
||||||
<a class="navbar-brand" href="#">Navbar</a>
|
|
||||||
<div class="collapse navbar-collapse" id="navbarNavDropdown">
|
|
||||||
<ul class="navbar-nav">
|
|
||||||
<li class="nav-item active">
|
|
||||||
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Features</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Pricing</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item dropdown">
|
|
||||||
<a class="nav-link dropdown-toggle" href="http://example.com" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
||||||
Dropdown link
|
|
||||||
</a>
|
|
||||||
<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
|
|
||||||
<a class="dropdown-item" href="#">Action</a>
|
|
||||||
<a class="dropdown-item" href="#">Another action</a>
|
|
||||||
<a class="dropdown-item" href="#">Something else here</a>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<div class="container-fluid">
|
|
||||||
<div class="row justify-content-center">
|
|
||||||
<!-- Fluid Gird, this login box stay in the middle of screen -->
|
|
||||||
<div class="col-5">
|
|
||||||
|
|
||||||
<div class="mainSection" ng-controller="loginCtrl">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-3 mainItem">
|
|
||||||
Username/Email
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col mainItem">
|
|
||||||
<input type="text" ng-model="username" >
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-3 mainItem">
|
|
||||||
Password
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col mainItem">
|
|
||||||
<input type="password" ng-model="password" >
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mainItem">
|
|
||||||
<button type="button" class="btn btn-primary" ng-click="signin()"> S2ign I1n </button>
|
|
||||||
|
|
||||||
<button type="button" class="btn btn-danger" ng-click="createAccount()">Create an account
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div><!-- Container fluid-->
|
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
app.controller('loginCtrl', function($scope,$state,$http,$rootScope,authService) {
|
|
||||||
/* login variables */
|
|
||||||
$scope.username = "user";
|
|
||||||
$scope.password = "Doe";
|
|
||||||
$scope.fullName = function() {
|
|
||||||
return $scope.firstName + " " + $scope.lastName;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 1. send request to server to authenticate login information
|
|
||||||
// 2. on succeed, redirect to page
|
|
||||||
// 2.1 on failed, display error message
|
|
||||||
$scope.signin = function(){
|
|
||||||
var foodloop_token_url_login = "http://192.168.2.172:3000/login";
|
|
||||||
var loginData = JSON.stringify({
|
|
||||||
email : this.username,
|
|
||||||
password: this.password
|
|
||||||
});
|
|
||||||
console.log("Attempting to login in");
|
|
||||||
|
|
||||||
$http.post(foodloop_token_url_login,loginData).success(function(repsonse){
|
|
||||||
console.log("Resolving response from server");
|
|
||||||
console.log(repsonse.data);
|
|
||||||
},function(repsonse){
|
|
||||||
console.log("Ooops, Something went wrong");
|
|
||||||
});
|
|
||||||
authService.setUsername($scope.username);
|
|
||||||
// $state.go("user");
|
|
||||||
// if($scope.username === "admin"){
|
|
||||||
// $state.go('admin');
|
|
||||||
// }
|
|
||||||
// else if($scope.username === "user"){
|
|
||||||
// $state.go('user');
|
|
||||||
// }
|
|
||||||
// else{
|
|
||||||
// $state.go('home');
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$scope.createAccount = function(){
|
|
||||||
|
|
||||||
console.log("Create account button clicked");
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
|
@ -1,7 +0,0 @@
|
||||||
{"objects":[
|
|
||||||
{"circle":{"coordinates":[54.0472, -2.8018]}},
|
|
||||||
{"circle":{"coordinates":[-41.29,174.76]}},
|
|
||||||
{"circle":{"coordinates":[-41.30,174.79]}},
|
|
||||||
{"circle":{"coordinates":[-41.27,174.80]}},
|
|
||||||
{"circle":{"coordinates":[-41.29,174.78]}}
|
|
||||||
]}
|
|
|
@ -1,3 +0,0 @@
|
||||||
#mapid { height: 180px; }
|
|
||||||
|
|
||||||
#map { width:600px; height: 600px }
|
|
|
@ -1,15 +0,0 @@
|
||||||
<div id="map" style="width: 100%; height: 400px"></div>
|
|
||||||
<br>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-6">
|
|
||||||
<button class="btn btn-secondary btn-block" type="button">Track my spent</button>
|
|
||||||
</div>
|
|
||||||
<div class="col-lg-6">
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" class="form-control" placeholder="Search for...">
|
|
||||||
<span class="input-group-btn">
|
|
||||||
<button class="btn btn-secondary" type="button">Go!</button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,61 +0,0 @@
|
||||||
app.controller('mapCtrl',function($scope,$http,uploadReceiptService) {
|
|
||||||
|
|
||||||
|
|
||||||
// data
|
|
||||||
var traderGeoData = [
|
|
||||||
{ Latitude:54.04,Longitude:2.80,trader:"sample_1" },
|
|
||||||
{ Latitude:54.04,Longitude:2.80,trader:"sample_2" },
|
|
||||||
{ Latitude:54.01,Longitude:2.78,trader:"sample_3" },
|
|
||||||
];
|
|
||||||
|
|
||||||
var map = L.map('map').setView([54.0472, -2.8018], 13);
|
|
||||||
mapLink =
|
|
||||||
'<a href="http://openstreetmap.org">OpenStreetMap</a>';
|
|
||||||
L.tileLayer(
|
|
||||||
'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
|
||||||
attribution: '© ' + mapLink + ' Contributors',
|
|
||||||
maxZoom: 18,
|
|
||||||
}).addTo(map);
|
|
||||||
|
|
||||||
var svgLayer = L.svg();
|
|
||||||
svgLayer.addTo(map);
|
|
||||||
|
|
||||||
var svg = d3.select("#map").select("svg");
|
|
||||||
var g = d3.select("#map").select("svg").select('g');
|
|
||||||
g.attr("class", "leaflet-zoom-hide");
|
|
||||||
|
|
||||||
|
|
||||||
/* We simply pick up the SVG from the map object */
|
|
||||||
var svg = d3.select("#map").select("svg"),
|
|
||||||
g = svg.append("g");
|
|
||||||
|
|
||||||
d3.json("../pages/map/circles.json", function(collection) {
|
|
||||||
/* Add a LatLng object to each item in the dataset */
|
|
||||||
collection.objects.forEach(function(d) {
|
|
||||||
d.LatLng = new L.LatLng(d.circle.coordinates[0],
|
|
||||||
d.circle.coordinates[1])
|
|
||||||
})
|
|
||||||
|
|
||||||
var feature = g.selectAll("circle")
|
|
||||||
.data(collection.objects)
|
|
||||||
.enter().append("circle")
|
|
||||||
.style("stroke", "black")
|
|
||||||
.style("opacity", .6)
|
|
||||||
.style("fill", "red")
|
|
||||||
.attr("r", 20);
|
|
||||||
|
|
||||||
map.on("viewreset", update);
|
|
||||||
update();
|
|
||||||
|
|
||||||
function update() {
|
|
||||||
console.log("update!");
|
|
||||||
feature.attr("transform",
|
|
||||||
function(d) {
|
|
||||||
return "translate("+
|
|
||||||
map.latLngToLayerPoint(d.LatLng).x +","+
|
|
||||||
map.latLngToLayerPoint(d.LatLng).y +")";
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,108 +0,0 @@
|
||||||
<main class="col-sm-9 offset-sm-3 col-md-10 offset-md-2 pt-3">
|
|
||||||
<form>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-7">
|
|
||||||
<div class="pearCard">
|
|
||||||
<div class="pearCardHeader .pearGreen">Fill in to submit </div>
|
|
||||||
<div class="padding16">
|
|
||||||
<!-- from group start -->
|
|
||||||
<div class="form-group row">
|
|
||||||
<label for="example-text-input" class="col-2 col-form-label">Store name</label>
|
|
||||||
<div class="col">
|
|
||||||
<input class="form-control" type="text" ng-model="storename" placeholder="e.g. Three" id="example-text-input">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group row">
|
|
||||||
<div class="col">
|
|
||||||
<div class="searchList">
|
|
||||||
<ul class="list-group" ng-repeat="store in storeList">
|
|
||||||
<li class="list-group-item ">{{store.store_id}}</li>
|
|
||||||
<li class="list-group-item ">{{store.store_name}}</li>
|
|
||||||
<li class="list-group-item ">{{store.store_address}}</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group row">
|
|
||||||
<label for="example-search-input" class="col-2 col-form-label">amount</label>
|
|
||||||
<div class="col">
|
|
||||||
<input class="form-control" type="decimal" ng-model="amount" placeholder="e.g. 6.66" id="example-search-input">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group row justify-content-center">
|
|
||||||
<label for="example-email-input" class="col col-form-label">Image(Click 'Add' button or Drag an image into the box below)</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<input type='file' ng-model ="receiptPhoto" accept="image/*"
|
|
||||||
onchange="angular.element(this).scope().getImage(this)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<div class="dragImageBox">
|
|
||||||
<div class="row no-gutters">
|
|
||||||
<img class="col-2 thumb" ng-src="{{receiptPhotoSrc}}"/>
|
|
||||||
<!-- image details, progress bar etc. -->
|
|
||||||
<div class="col-5 thumb">
|
|
||||||
filename:{{receiptPhoto.filename}}<br> filesize:{{receiptPhoto.filesize}}<br>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="pearCardFooter">
|
|
||||||
<button type="button" ng-click="uploadReceipt()" class="btn btn-primary"> Submit </button>
|
|
||||||
<button type="button" class="btn btn-danger"> Reset </button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- from group end -->
|
|
||||||
</div>
|
|
||||||
<!-- PADDING -->
|
|
||||||
</div>
|
|
||||||
<!-- pear card -->
|
|
||||||
</div>
|
|
||||||
<!-- first col-5 -->
|
|
||||||
|
|
||||||
<div class="col">
|
|
||||||
<div class="pearCard">
|
|
||||||
<div class="pearCardHeader pearOrange"> Pending receipt
|
|
||||||
<span class="badge badge-info">5 </span> </div>
|
|
||||||
<!-- content start here -->
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>#</th>
|
|
||||||
<th>When</th>
|
|
||||||
<th>Amount</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr ng-repeat="receipt in pending_list">
|
|
||||||
<td>{{$index + 1}}</td>
|
|
||||||
<td>{{receipt.submitted_time}}</td>
|
|
||||||
<td>{{receipt.submitted_amount}}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- second col -->
|
|
||||||
</div>
|
|
||||||
<!-- first row-->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</main>
|
|
|
@ -1,62 +0,0 @@
|
||||||
app.controller('receiptCtrl',function($scope,$http,uploadReceiptService) {
|
|
||||||
|
|
||||||
// display the list of all exsiting store, validated and not validated
|
|
||||||
$scope.storelist;
|
|
||||||
|
|
||||||
// require param for upload api
|
|
||||||
$scope.microCurrencyValue;
|
|
||||||
$scope.transactionAdditionType;
|
|
||||||
$scope.addValidatedId;
|
|
||||||
|
|
||||||
$scope.storename;
|
|
||||||
|
|
||||||
// photo and path to the photo
|
|
||||||
$scope.receiptPhoto;
|
|
||||||
$scope.receiptPhotoSrc;
|
|
||||||
|
|
||||||
// list of pending reciepts await for approval from admin
|
|
||||||
$scope.pending_list = [
|
|
||||||
{submitted_time: 30 },{submitted_time:20},{submitted_time:10},{submitted_time:5},{submitted_time:1}
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
var foodloop_token_url_search = "http://192.168.2.172:3000/search";
|
|
||||||
|
|
||||||
|
|
||||||
// get the latest store list
|
|
||||||
$scope.getStoreList = function(){
|
|
||||||
var data = {
|
|
||||||
"searchName": "",
|
|
||||||
"searchLocation": ""
|
|
||||||
};
|
|
||||||
$http.post(foodloop_token_url_search,data).then(function(response){
|
|
||||||
console.log(response);
|
|
||||||
});
|
|
||||||
|
|
||||||
// API call to /search to fetch a list of store
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.storelist = $scope.getStoreList();
|
|
||||||
|
|
||||||
// select the image
|
|
||||||
$scope.getImage = function(element) {
|
|
||||||
var reader = new FileReader();
|
|
||||||
reader.onload = function(event) {
|
|
||||||
$scope.$apply(function($scope) {
|
|
||||||
$scope.receiptPhoto = element.files[0];
|
|
||||||
$scope.receiptPhotoSrc = event.target.result
|
|
||||||
});
|
|
||||||
}
|
|
||||||
reader.readAsDataURL(element.files[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// upload the receipt to the server
|
|
||||||
$scope.uploadReceipt = function(){
|
|
||||||
uploadReceiptService.uploadReceipt();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// test
|
|
||||||
// firebase api to upload an image
|
|
||||||
|
|
||||||
});
|
|
|
@ -1,27 +0,0 @@
|
||||||
<nav class="navbar navbar-toggleable-md fixed-top navbar-inverse" style="background-color:#0091EA;">
|
|
||||||
<button class="navbar-toggler navbar-toggler-right hidden-lg-up" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
|
|
||||||
<span class="navbar-toggler-icon"></span>
|
|
||||||
</button>
|
|
||||||
<a class="navbar-brand" href="#">FoodLoop</a>
|
|
||||||
|
|
||||||
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
|
|
||||||
<ul class="navbar-nav mr-auto">
|
|
||||||
<li class="nav-item active">
|
|
||||||
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Settings</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Profile</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Help</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<form class="form-inline mt-2 mt-md-0">
|
|
||||||
<input class="form-control mr-sm-2" type="text" placeholder="Search">
|
|
||||||
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
|
@ -1,6 +0,0 @@
|
||||||
<main class="col-sm-9 offset-sm-3 col-md-10 offset-md-2 pt-3">
|
|
||||||
<div id="layouter">
|
|
||||||
i m the main content in trader page
|
|
||||||
</div>
|
|
||||||
<!-- Layouter -->
|
|
||||||
</main>
|
|
|
@ -1,44 +0,0 @@
|
||||||
<!-- This page defines a side bar for admin -->
|
|
||||||
<nav class="col-sm-3 col-md-2 hidden-xs-down bg-faded sidebar">
|
|
||||||
<ul class="nav nav-pills flex-column">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link active" href="#">Admin Portal <span class="sr-only">(current)</span></a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Add User</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Add Trader</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Sign out</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul class="nav nav-pills flex-column" id="meq">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link active" href="#">Receipt Management</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">View receipt</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Option 2</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Option 3</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul class="nav nav-pills flex-column">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Nav item again</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">One more nav</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Another nav item</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
|
@ -1,15 +0,0 @@
|
||||||
app.controller('traderCtrl', function($scope,$location) {
|
|
||||||
|
|
||||||
$scope.content = "I am not a header";
|
|
||||||
$scope.headerContent = "FoodLoop Admin Portal";
|
|
||||||
|
|
||||||
|
|
||||||
/* This block of code handles recepit management */
|
|
||||||
$scope.receiptNumber = 0;
|
|
||||||
|
|
||||||
|
|
||||||
/* This block of code handles user management */
|
|
||||||
/* Including the management of registered user, trader */
|
|
||||||
$scope.registeredUsers = 1;
|
|
||||||
|
|
||||||
});
|
|
|
@ -1,24 +0,0 @@
|
||||||
<nav class="navbar navbar-toggleable-md fixed-top navbar-inverse" style="background-color:#0091EA;">
|
|
||||||
<button class="navbar-toggler navbar-toggler-right hidden-lg-up" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
|
|
||||||
<span class="navbar-toggler-icon"></span>
|
|
||||||
</button>
|
|
||||||
<a class="navbar-brand" href="#">FoodLoop</a>
|
|
||||||
|
|
||||||
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
|
|
||||||
<ul class="navbar-nav mr-auto">
|
|
||||||
<li class="nav-item active">
|
|
||||||
<a class="nav-link" ui-sref="user">Home <span class="sr-only">(current)</span></a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" ui-sref=".settings">Settings</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href=".help">Help</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<form class="form-inline mt-2 mt-md-0">
|
|
||||||
<input class="form-control mr-sm-2" type="text" placeholder="Search">
|
|
||||||
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
Binary file not shown.
Before Width: | Height: | Size: 13 KiB |
|
@ -1,28 +0,0 @@
|
||||||
<main class="col-sm-9 offset-sm-3 col-md-10 offset-md-2 pt-3">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Position</th>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Pear points</th>
|
|
||||||
<th>Retailers spent with</th>
|
|
||||||
<th>Receipt submitted</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr ng-repeat="user in leaderboard">
|
|
||||||
<td>{{$index + 1}}</td>
|
|
||||||
<td>{{user.name}}</td>
|
|
||||||
<td>{{user.pear_points}}</td>
|
|
||||||
<td>{{user.retailer_spent}}</td>
|
|
||||||
<td>{{user.receipt_submitted}}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<!-- col -->
|
|
||||||
</div>
|
|
||||||
<!-- row first -->
|
|
||||||
</main>
|
|
|
@ -1,21 +0,0 @@
|
||||||
<main class="col-sm-9 offset-sm-3 col-md-10 offset-md-2 pt-3">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<div class="pearCard pearAutoHeight">
|
|
||||||
<div class="pearCardHeader"> Personal details </div>
|
|
||||||
<div class="pearCardContent">
|
|
||||||
<div class="row justify-content-center">
|
|
||||||
<div class="col-2">
|
|
||||||
<label>Username</label>
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<input type="text" placeholder="{{username}}">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- col -->
|
|
||||||
</div>
|
|
||||||
<!-- row first -->
|
|
||||||
</main>
|
|
|
@ -1,90 +0,0 @@
|
||||||
<main class="col-sm-9 offset-sm-3 col-md-10 offset-md-2 pt-3">
|
|
||||||
<!--display my ranking -->
|
|
||||||
<div class="row">
|
|
||||||
|
|
||||||
<div class="col-3">
|
|
||||||
<div class="flCard">
|
|
||||||
<div class="flCardHeader">
|
|
||||||
<div class="title">Rank</div>
|
|
||||||
</div>
|
|
||||||
<div class="flCardMain"> 1 </div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-3">
|
|
||||||
<div class="flCard">
|
|
||||||
<div class="flCardHeader">Points</div>
|
|
||||||
<div class="flCardMain"> 888 </div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-3">
|
|
||||||
<div class="flCard">
|
|
||||||
<div class="flCardHeader">Spend</div>
|
|
||||||
<div class="flCardMain"> £100 </div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="col-3">
|
|
||||||
<div class="flCard">
|
|
||||||
<div class="flCardHeader">Re-spend</div>
|
|
||||||
<div class="flCardMain"> £5.00 </div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- first row end -->
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="col-3">
|
|
||||||
<div class="pearCard margin16">
|
|
||||||
<div class="pearCardHeader"> My receipt </div>
|
|
||||||
<div class="receiptItem">
|
|
||||||
Pending receipt <span class="badge badge-danger">5</span>
|
|
||||||
</div>
|
|
||||||
<div class="receiptItem">
|
|
||||||
Submit a receipt
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="col-5">
|
|
||||||
<div class="pearCard margin16">
|
|
||||||
<div class="pearCardHeader"> Personal overview </div>
|
|
||||||
<flChart> </flChart>
|
|
||||||
<canvas id="myChart"></canvas>
|
|
||||||
</div>
|
|
||||||
<!-- flCard-->
|
|
||||||
</div>
|
|
||||||
<!-- col-5 receipt-->
|
|
||||||
|
|
||||||
<div class="col">
|
|
||||||
<div class="pearCard margin16">
|
|
||||||
<div class="pearCardHeader"> Top players of the month </div>
|
|
||||||
<div class="rankCardContent">
|
|
||||||
<table class="table table-hover">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>#</th>
|
|
||||||
<th>Username</th>
|
|
||||||
<th>Points</th>
|
|
||||||
<th>Receipts submitted</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- col for pending receipt -->
|
|
||||||
</div>
|
|
||||||
<!-- row -->
|
|
||||||
<!--<button ng-click="displayChart()"> Hit me </button>-->
|
|
||||||
</main>
|
|
|
@ -1,30 +0,0 @@
|
||||||
<!-- This page defines a side bar for admin -->
|
|
||||||
<nav class="col-sm-3 col-md-2 hidden-xs-down bg-faded sidebar">
|
|
||||||
|
|
||||||
<!--<div class="row no-gutters">
|
|
||||||
<div class="col-5">
|
|
||||||
<div class="profilePic">
|
|
||||||
<img src="../../pages/user/icon1.png" class="profile-pic">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-7">
|
|
||||||
<div class="profileInfo">
|
|
||||||
<h6>{{username}}</h6>
|
|
||||||
<div class="profileTitle">{{email}}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>-->
|
|
||||||
|
|
||||||
<ul class="nav nav-pills flex-column" id="meq">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link active" href="#">Key features</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" ui-sref=".receipt">Submit a receipt</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" ui-sref=".leaderboard">View Leaderboard</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</nav>
|
|
|
@ -1,3 +0,0 @@
|
||||||
<user-header> </user-header>
|
|
||||||
<user-sidebar> </user-sidebar>
|
|
||||||
<user-main> </user-main>
|
|
|
@ -1,65 +0,0 @@
|
||||||
app.controller('userCtrl', function($scope,$location) {
|
|
||||||
$scope.user_rank = 1;
|
|
||||||
$scope.controllby = "user";
|
|
||||||
$scope.username = "John Smith";
|
|
||||||
$scope.email = "test007@test.com";
|
|
||||||
$scope.createChart = function(){
|
|
||||||
var ctx = document.getElementById("myChart");
|
|
||||||
var myChart = new Chart(ctx, {
|
|
||||||
type: 'line',
|
|
||||||
data: {
|
|
||||||
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
|
|
||||||
datasets: [{
|
|
||||||
label: '# of Votes',
|
|
||||||
data: [12, 19, 3, 5, 2, 3],
|
|
||||||
backgroundColor: [
|
|
||||||
'rgba(255, 99, 132, 0.2)',
|
|
||||||
'rgba(54, 162, 235, 0.2)',
|
|
||||||
'rgba(255, 206, 86, 0.2)',
|
|
||||||
'rgba(75, 192, 192, 0.2)',
|
|
||||||
'rgba(153, 102, 255, 0.2)',
|
|
||||||
'rgba(255, 159, 64, 0.2)'
|
|
||||||
],
|
|
||||||
borderColor: [
|
|
||||||
'rgba(255,99,132,1)',
|
|
||||||
'rgba(54, 162, 235, 1)',
|
|
||||||
'rgba(255, 206, 86, 1)',
|
|
||||||
'rgba(75, 192, 192, 1)',
|
|
||||||
'rgba(153, 102, 255, 1)',
|
|
||||||
'rgba(255, 159, 64, 1)'
|
|
||||||
],
|
|
||||||
borderWidth: 1
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
scales: {
|
|
||||||
yAxes: [{
|
|
||||||
ticks: {
|
|
||||||
beginAtZero:true
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$scope.displayChart = function(){
|
|
||||||
// chart sample
|
|
||||||
var flData = [{x: 100, y: 100}, {x: 200, y: 200}, {x: 300, y: 300}];
|
|
||||||
var svg = d3.select("flChart").append("svg")
|
|
||||||
.attr("width","300px").attr("height","300px");
|
|
||||||
svg
|
|
||||||
.selectAll("circle").data(flData)
|
|
||||||
.enter().append("circle")
|
|
||||||
.attr("cx", function(d) { return d.x; })
|
|
||||||
.attr("cy", function(d) { return d.y; })
|
|
||||||
.attr("r", 2.5);
|
|
||||||
|
|
||||||
console.log(svg);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
30
protractor.conf.js
Normal file
30
protractor.conf.js
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// Protractor configuration file, see link for more information
|
||||||
|
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||||
|
|
||||||
|
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||||
|
|
||||||
|
exports.config = {
|
||||||
|
allScriptsTimeout: 11000,
|
||||||
|
specs: [
|
||||||
|
'./e2e/**/*.e2e-spec.ts'
|
||||||
|
],
|
||||||
|
capabilities: {
|
||||||
|
'browserName': 'chrome'
|
||||||
|
},
|
||||||
|
directConnect: true,
|
||||||
|
baseUrl: 'http://localhost:4200/',
|
||||||
|
framework: 'jasmine',
|
||||||
|
jasmineNodeOpts: {
|
||||||
|
showColors: true,
|
||||||
|
defaultTimeoutInterval: 30000,
|
||||||
|
print: function() {}
|
||||||
|
},
|
||||||
|
beforeLaunch: function() {
|
||||||
|
require('ts-node').register({
|
||||||
|
project: 'e2e/tsconfig.e2e.json'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onPrepare() {
|
||||||
|
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,14 +0,0 @@
|
||||||
/* this service handles all the authentication between client and server */
|
|
||||||
app.service('authService', function ($http) {
|
|
||||||
// send a login information to server
|
|
||||||
// upon success, set sessionToken and store data in dataService
|
|
||||||
// upon failed, return error
|
|
||||||
this.username = "";
|
|
||||||
this.getUsername = function(){
|
|
||||||
return this.username;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setUsername = function(setTo){
|
|
||||||
this.username = setTo;
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,56 +0,0 @@
|
||||||
/* this service handles all the authentication between client and server */
|
|
||||||
app.service('chartService', function () {
|
|
||||||
// send a login information to server
|
|
||||||
// upon success, set sessionToken and store data in dataService
|
|
||||||
// upon failed, return error
|
|
||||||
this.username = "";
|
|
||||||
this.getUsername = function(){
|
|
||||||
return this.username;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setUsername = function(setTo){
|
|
||||||
this.username = setTo;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
this.createChart = function(){
|
|
||||||
var ctx = document.getElementById("myChart");
|
|
||||||
var myChart = new Chart(ctx, {
|
|
||||||
type: 'line',
|
|
||||||
data: {
|
|
||||||
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
|
|
||||||
datasets: [{
|
|
||||||
label: '# of Votes',
|
|
||||||
data: [12, 19, 3, 5, 2, 3],
|
|
||||||
backgroundColor: [
|
|
||||||
'rgba(255, 99, 132, 0.2)',
|
|
||||||
'rgba(54, 162, 235, 0.2)',
|
|
||||||
'rgba(255, 206, 86, 0.2)',
|
|
||||||
'rgba(75, 192, 192, 0.2)',
|
|
||||||
'rgba(153, 102, 255, 0.2)',
|
|
||||||
'rgba(255, 159, 64, 0.2)'
|
|
||||||
],
|
|
||||||
borderColor: [
|
|
||||||
'rgba(255,99,132,1)',
|
|
||||||
'rgba(54, 162, 235, 1)',
|
|
||||||
'rgba(255, 206, 86, 1)',
|
|
||||||
'rgba(75, 192, 192, 1)',
|
|
||||||
'rgba(153, 102, 255, 1)',
|
|
||||||
'rgba(255, 159, 64, 1)'
|
|
||||||
],
|
|
||||||
borderWidth: 1
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
scales: {
|
|
||||||
yAxes: [{
|
|
||||||
ticks: {
|
|
||||||
beginAtZero:true
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,6 +0,0 @@
|
||||||
/* this service handles receipt upload process */
|
|
||||||
app.service('uploadReceiptService', function () {
|
|
||||||
this.uploadReceipt = function(){
|
|
||||||
console.log("Upload successful");
|
|
||||||
}
|
|
||||||
});
|
|
21
src/app/_guards/auth.guard.ts
Normal file
21
src/app/_guards/auth.guard.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AuthGuard implements CanActivate {
|
||||||
|
|
||||||
|
constructor(private router: Router) { }
|
||||||
|
|
||||||
|
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||||
|
if (localStorage.getItem('sessionKey')) {
|
||||||
|
console.log('session key found')
|
||||||
|
// logged in so return true
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// not logged in so redirect to login page with the return url
|
||||||
|
console.log('no session key found')
|
||||||
|
this.router.navigate(['/login'], { queryParams: { returnUrl: state.url }});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
22
src/app/_guards/customer.guard.ts
Normal file
22
src/app/_guards/customer.guard.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class CustomerGuard implements CanActivate {
|
||||||
|
|
||||||
|
constructor(private router: Router) { }
|
||||||
|
|
||||||
|
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||||
|
if (localStorage.getItem('usertype') === 'customer') {
|
||||||
|
console.log('Customer logged in');
|
||||||
|
// customer logged in so return true
|
||||||
|
return true;
|
||||||
|
} else if (localStorage.getItem('usertype') === 'organisation') {
|
||||||
|
console.log('not an customer');
|
||||||
|
this.router.navigate(['/dashboard']);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.router.navigate(['/login']);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
22
src/app/_guards/org.guard.ts
Normal file
22
src/app/_guards/org.guard.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class OrgGuard implements CanActivate {
|
||||||
|
|
||||||
|
constructor(private router: Router) { }
|
||||||
|
|
||||||
|
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||||
|
if (localStorage.getItem('usertype') === 'organisation') {
|
||||||
|
console.log('Organisation logged in');
|
||||||
|
// org logged in so return true
|
||||||
|
return true;
|
||||||
|
} else if (localStorage.getItem('usertype') === 'customer') {
|
||||||
|
console.log('not an organisation');
|
||||||
|
this.router.navigate(['/dashboard-customer']);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.router.navigate(['/login']);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
4
src/app/_interfaces/chart-data.ts
Normal file
4
src/app/_interfaces/chart-data.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export interface ChartData {
|
||||||
|
data: Array<number>;
|
||||||
|
label: string;
|
||||||
|
}
|
44
src/app/app.component.spec.ts
Normal file
44
src/app/app.component.spec.ts
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import { TestBed, ComponentFixture, async } from '@angular/core/testing';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { DebugElement } from '@angular/core';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
|
||||||
|
// Items under test
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
|
||||||
|
describe('AppComponent', () => {
|
||||||
|
let fixture: ComponentFixture<AppComponent>;
|
||||||
|
let app: AppComponent;
|
||||||
|
let de: DebugElement;
|
||||||
|
let appDocument: any;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed
|
||||||
|
.configureTestingModule({
|
||||||
|
declarations: [
|
||||||
|
AppComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
RouterTestingModule.withRoutes(
|
||||||
|
[{path: '', component: AppComponent}]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(AppComponent);
|
||||||
|
app = fixture.componentInstance;
|
||||||
|
de = fixture.debugElement;
|
||||||
|
appDocument = de.nativeElement;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create the app', async(() => {
|
||||||
|
expect(app).toBeTruthy();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should have a router-outlet', async(() => {
|
||||||
|
expect(appDocument.querySelector('router-outlet')).toBeTruthy();
|
||||||
|
}));
|
||||||
|
});
|
7
src/app/app.component.ts
Normal file
7
src/app/app.component.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-root',
|
||||||
|
template: '<router-outlet></router-outlet>'
|
||||||
|
})
|
||||||
|
export class AppComponent { }
|
75
src/app/app.module.ts
Normal file
75
src/app/app.module.ts
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { LocationStrategy, HashLocationStrategy } from '@angular/common';
|
||||||
|
import { HttpModule } from '@angular/http';
|
||||||
|
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
|
||||||
|
import { TabsModule } from 'ngx-bootstrap/tabs';
|
||||||
|
import { NgxPaginationModule } from 'ngx-pagination';
|
||||||
|
import { NAV_DROPDOWN_DIRECTIVES } from './shared/nav-dropdown.directive';
|
||||||
|
|
||||||
|
import { SIDEBAR_TOGGLE_DIRECTIVES } from './shared/sidebar.directive';
|
||||||
|
import { AsideToggleDirective } from './shared/aside.directive';
|
||||||
|
import { BreadcrumbsComponent } from './shared/breadcrumb.component';
|
||||||
|
|
||||||
|
// Routing & Guard Module
|
||||||
|
import { AppRoutingModule } from './app.routing';
|
||||||
|
import { AuthGuard } from './_guards/auth.guard';
|
||||||
|
import { OrgGuard } from './_guards/org.guard';
|
||||||
|
import { CustomerGuard } from './_guards/customer.guard';
|
||||||
|
import { ApiService } from './providers/api-service';
|
||||||
|
|
||||||
|
import { OrgGraphsService } from './providers/org-graphs.service';
|
||||||
|
import { OrgSnippetsService } from './providers/org-snippets.service';
|
||||||
|
|
||||||
|
// Layouts
|
||||||
|
import { FullLayoutComponent } from './layouts/full-layout.component';
|
||||||
|
import { SimpleLayoutComponent } from './layouts/simple-layout.component';
|
||||||
|
|
||||||
|
// Error Pages
|
||||||
|
import { P404Component } from './pages/404.component';
|
||||||
|
import { P500Component } from './pages/500.component';
|
||||||
|
|
||||||
|
// Submodules
|
||||||
|
import { AuthModule } from './auth/auth.module';
|
||||||
|
import { DashboardModule } from './dashboard/dashboard.module';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
BrowserModule,
|
||||||
|
HttpModule,
|
||||||
|
NgxPaginationModule,
|
||||||
|
BsDropdownModule.forRoot(),
|
||||||
|
TabsModule.forRoot(),
|
||||||
|
AuthModule,
|
||||||
|
DashboardModule,
|
||||||
|
// Loaded last to allow for 404 catchall
|
||||||
|
AppRoutingModule,
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
AppComponent,
|
||||||
|
FullLayoutComponent,
|
||||||
|
SimpleLayoutComponent,
|
||||||
|
NAV_DROPDOWN_DIRECTIVES,
|
||||||
|
BreadcrumbsComponent,
|
||||||
|
SIDEBAR_TOGGLE_DIRECTIVES,
|
||||||
|
AsideToggleDirective,
|
||||||
|
P404Component,
|
||||||
|
P500Component,
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
AuthGuard,
|
||||||
|
OrgGuard,
|
||||||
|
CustomerGuard,
|
||||||
|
ApiService,
|
||||||
|
OrgGraphsService,
|
||||||
|
OrgSnippetsService,
|
||||||
|
{
|
||||||
|
provide: LocationStrategy,
|
||||||
|
useClass: HashLocationStrategy
|
||||||
|
}
|
||||||
|
],
|
||||||
|
bootstrap: [ AppComponent ]
|
||||||
|
})
|
||||||
|
export class AppModule { }
|
17
src/app/app.routing.ts
Normal file
17
src/app/app.routing.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { Routes, RouterModule } from '@angular/router';
|
||||||
|
|
||||||
|
import { P404Component } from './pages/404.component';
|
||||||
|
import { P500Component } from './pages/500.component';
|
||||||
|
|
||||||
|
export const routes: Routes = [
|
||||||
|
{ path: '404', component: P404Component },
|
||||||
|
{ path: '500', component: P500Component },
|
||||||
|
{ path: '**', redirectTo: '/404' },
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [ RouterModule.forRoot(routes) ],
|
||||||
|
exports: [ RouterModule ]
|
||||||
|
})
|
||||||
|
export class AppRoutingModule {}
|
21
src/app/auth/auth.module.ts
Normal file
21
src/app/auth/auth.module.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
import { LoginComponent } from './login.component';
|
||||||
|
import { RegisterComponent } from './register.component';
|
||||||
|
import { AuthRoutingModule } from './auth.routing';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
FormsModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
AuthRoutingModule,
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
LoginComponent,
|
||||||
|
RegisterComponent,
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AuthModule {}
|
15
src/app/auth/auth.routing.ts
Normal file
15
src/app/auth/auth.routing.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { Routes, RouterModule } from '@angular/router';
|
||||||
|
import { LoginComponent } from './login.component';
|
||||||
|
import { RegisterComponent } from './register.component';
|
||||||
|
|
||||||
|
const authRoutes: Routes = [
|
||||||
|
{ path: 'login', component: LoginComponent },
|
||||||
|
{ path: 'register', component: RegisterComponent },
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [ RouterModule.forChild(authRoutes) ],
|
||||||
|
exports: [ RouterModule ],
|
||||||
|
})
|
||||||
|
export class AuthRoutingModule {}
|
53
src/app/auth/login.component.html
Normal file
53
src/app/auth/login.component.html
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
<div class="app flex-row align-items-center">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="card-group mb-0">
|
||||||
|
<div class="card p-4">
|
||||||
|
<div class="card-block">
|
||||||
|
<h1>Login</h1>
|
||||||
|
<p class="text-muted">Sign In to your account</p>
|
||||||
|
<form [formGroup]="signin" (ngSubmit)="onSubmit()">
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-addon">@</span>
|
||||||
|
<input id="username" type="text" class="form-control" formControlName="email" placeholder="Email">
|
||||||
|
</div>
|
||||||
|
<div class="input-group mb-4">
|
||||||
|
<span class="input-group-addon"><i class="icon-lock"></i></span>
|
||||||
|
<input id="password" type="password" class="form-control" formControlName="password" placeholder="Password">
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<div [ngSwitch]="loginStatus">
|
||||||
|
<div *ngSwitchCase="'success'" class="alert alert-success" role="alert">
|
||||||
|
Login Succeeded, routing to homepage.
|
||||||
|
</div>
|
||||||
|
<div *ngSwitchCase="'send_failed'" class="alert alert-danger" role="alert">
|
||||||
|
Error received, please try again.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6">
|
||||||
|
<button type="submit" [disabled]="!signin.valid" class="btn btn-primary px-4">Login</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-6 text-right">
|
||||||
|
<button type="button" class="btn btn-link px-0">Forgot password?</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card card-inverse card-primary py-5 d-md-down-none" style="width:44%">
|
||||||
|
<div class="card-block text-center">
|
||||||
|
<div>
|
||||||
|
<h2>Sign up</h2>
|
||||||
|
<p>Click the "Register Now" button to register your user account. Be sure to have a token!</p>
|
||||||
|
<button type="button" class="btn btn-primary active mt-3" routerLinkActive="active" [routerLink]="['/register']">Register Now!</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
63
src/app/auth/login.component.ts
Normal file
63
src/app/auth/login.component.ts
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Validators, FormBuilder, FormGroup } from '@angular/forms';
|
||||||
|
import { Http, Response } from '@angular/http';
|
||||||
|
import { ApiService } from '../providers/api-service';
|
||||||
|
import { Router, ActivatedRoute } from '@angular/router';
|
||||||
|
import 'rxjs/add/operator/map';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: 'login.component.html',
|
||||||
|
})
|
||||||
|
export class LoginComponent implements OnInit {
|
||||||
|
signin: FormGroup;
|
||||||
|
returnUrl: string;
|
||||||
|
loginStatus: any;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private http: Http,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private router: Router,
|
||||||
|
private api: ApiService
|
||||||
|
) {
|
||||||
|
this.signin = this.formBuilder.group({
|
||||||
|
email: ['', [Validators.required]],
|
||||||
|
password: ['', [Validators.required]],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
// reset login status
|
||||||
|
this.api
|
||||||
|
.logout()
|
||||||
|
.subscribe(
|
||||||
|
result => {
|
||||||
|
console.log('Logged out!');
|
||||||
|
localStorage.clear();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// get return url from route parameters or default to '/'
|
||||||
|
this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit() {
|
||||||
|
console.log(this.signin.value);
|
||||||
|
|
||||||
|
this.api
|
||||||
|
.login(this.signin.value)
|
||||||
|
.subscribe(
|
||||||
|
result => {
|
||||||
|
console.log('logged in!');
|
||||||
|
this.loginStatus = 'success';
|
||||||
|
console.log(this.loginStatus);
|
||||||
|
this.router.navigate([this.returnUrl]);
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log( error._body );
|
||||||
|
this.loginStatus = 'send_failed';
|
||||||
|
console.log(this.loginStatus);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
148
src/app/auth/register.component.html
Normal file
148
src/app/auth/register.component.html
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
<div class="app flex-row align-items-center">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="card mx-4">
|
||||||
|
<div class="card-block p-4">
|
||||||
|
<h1>Register</h1>
|
||||||
|
<p class="text-muted">Create your account</p>
|
||||||
|
|
||||||
|
<!-- <div class="input-group mb-3">
|
||||||
|
<span class="input-group-addon"><i class="icon-people"></i></span>
|
||||||
|
<select required class="form-control" type="text" formControlName="usertype">
|
||||||
|
<option value=''>Please select</option>
|
||||||
|
<option value='organisation'>Organisation</option>
|
||||||
|
<option value='customer'>Customer</option>
|
||||||
|
</select>
|
||||||
|
</div> -->
|
||||||
|
<form [formGroup]="signupForm.getForm()">
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-addon"><i class="icon-key"></i></span>
|
||||||
|
<input type="text" class="form-control" formControlName="token" placeholder="Token">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-addon">@</span>
|
||||||
|
<input type="text" class="form-control" formControlName="email" placeholder="Email">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-addon"><i class="icon-lock"></i></span>
|
||||||
|
<input type="password" class="form-control" formControlName="password" placeholder="Password">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group mb-4">
|
||||||
|
<span class="input-group-addon"><i class="icon-lock"></i></span>
|
||||||
|
<input type="password" class="form-control" formControlName="confirmpassword" placeholder="Repeat password">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-addon"><i class="icon-people"></i></span>
|
||||||
|
<select required class="form-control" type="text" formControlName="usertype">
|
||||||
|
<option value=''>Please select</option>
|
||||||
|
<option value='organisation'>Organisation</option>
|
||||||
|
<option value='customer'>Customer</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div [ngSwitch]="signupForm.getForm().value.usertype">
|
||||||
|
<div *ngSwitchCase="'customer'" >
|
||||||
|
<form [formGroup]="customerForm.getForm()" (ngSubmit)="onSubmitCustomer()">
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-addon"><i class="icon-user"></i></span>
|
||||||
|
<input type="text" class="form-control" formControlName="display_name" placeholder="Display Name">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-addon"><i class="icon-user"></i></span>
|
||||||
|
<input type="text" class="form-control" formControlName="full_name" placeholder="Full Name">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-addon"><i class="icon-user"></i></span>
|
||||||
|
<input type="text" class="form-control" formControlName="postcode" placeholder="Postcode">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-addon">Year of Birth</span>
|
||||||
|
<select class="form-control" type="text" formControlName="year_of_birth">
|
||||||
|
<option *ngFor="let range of years" [value]="range">{{ range }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-block btn-success">Create Account</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div *ngSwitchCase="'organisation'">
|
||||||
|
<form [formGroup]="organisationForm.getForm()" (ngSubmit)="onSubmitOrganisation()">
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-addon"><i class="icon-user"></i></span>
|
||||||
|
<input type="text" class="form-control" formControlName="name" placeholder="Organisation Name">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Uses the UK SIC 2007 classifications for sector as used by ONS -->
|
||||||
|
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<select required class="form-control" type="text" formControlName="sector">
|
||||||
|
<option value=''>Select Organisation Sector</option>
|
||||||
|
<option value='A'>Agriculture, Forestry & Fishing</option>
|
||||||
|
<option value='B'>Mining & Quarrying</option>
|
||||||
|
<option value='C'>Manufacturing</option>
|
||||||
|
<option value='D'>Electricity, Gas, Steam & Air Conditioning</option>
|
||||||
|
<option value='E'>Water & Waste Management</option>
|
||||||
|
<option value='F'>Construction</option>
|
||||||
|
<option value='G'>Wholesale & Retail Trade</option>
|
||||||
|
<option value='H'>Transportation & Storage</option>
|
||||||
|
<option value='I'>Accomodation & Food Services</option>
|
||||||
|
<option value='J'>Information & Communication</option>
|
||||||
|
<option value='K'>Financial & Insurance Activities</option>
|
||||||
|
<option value='L'>Real Estate</option>
|
||||||
|
<option value='M'>Professional, Scientfic & Technical</option>
|
||||||
|
<option value='N'>Administrative & Support Services</option>
|
||||||
|
<option value='O'>Public Administration, Defence & Social Security</option>
|
||||||
|
<option value='P'>Education</option>
|
||||||
|
<option value='Q'>Human Health & Social Work</option>
|
||||||
|
<option value='R'>Arts, Entertainment & Recreation</option>
|
||||||
|
<option value='S'>Other Service Activities</option>
|
||||||
|
<option value='T'>Household Domestic Business</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-addon"><i class="icon-user"></i></span>
|
||||||
|
<input type="text" class="form-control" formControlName="street_name" placeholder="Street Name">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-addon"><i class="icon-user"></i></span>
|
||||||
|
<input type="text" class="form-control" formControlName="town" placeholder="Town">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-addon"><i class="icon-user"></i></span>
|
||||||
|
<input type="text" class="form-control" formControlName="postcode" placeholder="Postcode">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-block btn-success">Create Account</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div heading="Pending" *ngSwitchDefault>Please Select a User Type</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3" [ngSwitch]="registerStatus">
|
||||||
|
<div *ngSwitchCase="'success'" class="alert alert-success" role="alert">
|
||||||
|
Register Succeeded.
|
||||||
|
</div>
|
||||||
|
<div *ngSwitchCase="'validation_failed'" class="alert alert-danger" role="alert">
|
||||||
|
Form validation failed, please ensure the form is filled correctly.
|
||||||
|
</div>
|
||||||
|
<div *ngSwitchCase="'send_failed'" class="alert alert-danger" role="alert">
|
||||||
|
Failed to send to server, please try again later.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
136
src/app/auth/register.component.ts
Normal file
136
src/app/auth/register.component.ts
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { Validators, FormBuilder, FormGroup } from '@angular/forms';
|
||||||
|
import { ValidationManager } from "ng2-validation-manager";
|
||||||
|
import { Http, Response } from '@angular/http';
|
||||||
|
import { ApiService } from '../providers/api-service';
|
||||||
|
import {Router } from '@angular/router';
|
||||||
|
import 'rxjs/add/operator/map';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: 'register.component.html',
|
||||||
|
})
|
||||||
|
|
||||||
|
export class RegisterComponent {
|
||||||
|
signupForm: ValidationManager;
|
||||||
|
customerForm: ValidationManager;
|
||||||
|
organisationForm: ValidationManager;
|
||||||
|
years: Object[];
|
||||||
|
registerStatus: any;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private http: Http,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private router: Router,
|
||||||
|
private api: ApiService,
|
||||||
|
) {
|
||||||
|
this.years = [];
|
||||||
|
let max = new Date().getFullYear() - 10,
|
||||||
|
min = max - 140;
|
||||||
|
|
||||||
|
for (let i = max; i>=min; i--){
|
||||||
|
this.years.push(i);
|
||||||
|
}
|
||||||
|
this.signupForm = new ValidationManager({
|
||||||
|
token: 'required',
|
||||||
|
usertype: 'required',
|
||||||
|
email: 'required|email',
|
||||||
|
password: 'required',
|
||||||
|
confirmpassword: 'required|equalTo:password'
|
||||||
|
});
|
||||||
|
this.customerForm = new ValidationManager({
|
||||||
|
display_name: 'required',
|
||||||
|
full_name: 'required',
|
||||||
|
postcode: 'required',
|
||||||
|
year_of_birth:'required',
|
||||||
|
});
|
||||||
|
this.organisationForm = new ValidationManager({
|
||||||
|
name: 'required',
|
||||||
|
sector: 'required',
|
||||||
|
street_name: 'required',
|
||||||
|
town: 'required',
|
||||||
|
postcode: 'required',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmitCustomer() {
|
||||||
|
|
||||||
|
console.log(this.signupForm.isValid());
|
||||||
|
if (!this.signupForm.isValid() && !this.customerForm.isValid()) {
|
||||||
|
console.log("Not Valid!");
|
||||||
|
this.registerStatus = "validation_failed";
|
||||||
|
console.log(this.registerStatus);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let signupForm = this.signupForm.getForm().value;
|
||||||
|
let customerForm = this.customerForm.getForm().value;
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
token: signupForm.token,
|
||||||
|
usertype: signupForm.usertype,
|
||||||
|
email: signupForm.email,
|
||||||
|
password: signupForm.password,
|
||||||
|
display_name: customerForm.display_name,
|
||||||
|
full_name: customerForm.full_name,
|
||||||
|
postcode: customerForm.postcode,
|
||||||
|
year_of_birth:customerForm.year_of_birth,
|
||||||
|
};
|
||||||
|
console.log(data);
|
||||||
|
this.api
|
||||||
|
.register(data)
|
||||||
|
.subscribe(
|
||||||
|
result => {
|
||||||
|
console.log('registered!');
|
||||||
|
this.registerStatus = "success";
|
||||||
|
console.log(this.registerStatus);
|
||||||
|
this.router.navigate(['/dashboard']);
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log( error._body );
|
||||||
|
this.registerStatus = "send_failed";
|
||||||
|
console.log(this.registerStatus)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
onSubmitOrganisation() {
|
||||||
|
|
||||||
|
console.log(this.signupForm.isValid());
|
||||||
|
if (!this.signupForm.isValid() || !this.organisationForm.isValid()) {
|
||||||
|
console.log("Not Valid!");
|
||||||
|
this.registerStatus = "validation_failed";
|
||||||
|
console.log(this.registerStatus);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let signupForm = this.signupForm.getForm().value;
|
||||||
|
let organisationForm = this.organisationForm.getForm().value;
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
token: signupForm.token,
|
||||||
|
usertype: signupForm.usertype,
|
||||||
|
email: signupForm.email,
|
||||||
|
password: signupForm.password,
|
||||||
|
name: organisationForm.name,
|
||||||
|
sector: organisationForm.sector,
|
||||||
|
street_name: organisationForm.street_name,
|
||||||
|
town: organisationForm.town,
|
||||||
|
postcode: organisationForm.postcode,
|
||||||
|
};
|
||||||
|
console.log(data);
|
||||||
|
this.api
|
||||||
|
.register(data)
|
||||||
|
.subscribe(
|
||||||
|
result => {
|
||||||
|
console.log('registered!');
|
||||||
|
this.registerStatus = "success";
|
||||||
|
console.log(this.registerStatus);
|
||||||
|
this.router.navigate(['/dashboard']);
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log( error._body );
|
||||||
|
this.registerStatus = "send_failed";
|
||||||
|
console.log(this.registerStatus);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
176
src/app/dashboard/account-edit.component.html
Normal file
176
src/app/dashboard/account-edit.component.html
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
<div class="animated fadeIn">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<strong>Update Account Info</strong>
|
||||||
|
<small>Required Data marked in <strong>bold</strong>.</small>
|
||||||
|
</div>
|
||||||
|
<form class="form-horizontal" [formGroup]="settingForm">
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Confirm Current Password</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="password" class="form-control" formControlName="password">
|
||||||
|
<span class="help-block">Required for security purposes.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Email</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="text" class="form-control" formControlName="email">
|
||||||
|
<span class="help-block">Change this to alter your current account email.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input">Enter New Password</label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="password" class="form-control" formControlName="new_password">
|
||||||
|
<span class="help-block">Enter a new password here if you wish to alter your current one.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Postcode</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="text" class="form-control" formControlName="postcode">
|
||||||
|
<span class="help-block">Change this if your location of residence has changed.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- <div class="card-block">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="file-input">Profile Picture</label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="file" #fileInput formControlName="profile_picture">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
</form>
|
||||||
|
<div [ngSwitch]="accountType">
|
||||||
|
<div *ngSwitchCase="'organisation'">
|
||||||
|
<form class="form-horizontal" [formGroup]="settingOrganisationForm" (ngSubmit)="onSubmitOrganisation()">
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Business Name</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="text" class="form-control" formControlName="name">
|
||||||
|
<span class="help-block">Change this if your business name has changed.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Street Name</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="text" class="form-control" formControlName="street_name">
|
||||||
|
<span class="help-block">Change this if your located street has changed.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Industry Sector</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<select required class="form-control" type="text" formControlName="sector">
|
||||||
|
<option value=''>Select Organisation Sector</option>
|
||||||
|
<option value='A'>Agriculture, Forestry & Fishing</option>
|
||||||
|
<option value='B'>Mining & Quarrying</option>
|
||||||
|
<option value='C'>Manufacturing</option>
|
||||||
|
<option value='D'>Electricity, Gas, Steam & Air Conditioning</option>
|
||||||
|
<option value='E'>Water & Waste Management</option>
|
||||||
|
<option value='F'>Construction</option>
|
||||||
|
<option value='G'>Wholesale & Retail Trade</option>
|
||||||
|
<option value='H'>Transportation & Storage</option>
|
||||||
|
<option value='I'>Accomodation & Food Services</option>
|
||||||
|
<option value='J'>Information & Communication</option>
|
||||||
|
<option value='K'>Financial & Insurance Activities</option>
|
||||||
|
<option value='L'>Real Estate</option>
|
||||||
|
<option value='M'>Professional, Scientfic & Technical</option>
|
||||||
|
<option value='N'>Administrative & Support Services</option>
|
||||||
|
<option value='O'>Public Administration, Defence & Social Security</option>
|
||||||
|
<option value='P'>Education</option>
|
||||||
|
<option value='Q'>Human Health & Social Work</option>
|
||||||
|
<option value='R'>Arts, Entertainment & Recreation</option>
|
||||||
|
<option value='S'>Other Service Activities</option>
|
||||||
|
<option value='T'>Household Domestic Business</option>
|
||||||
|
</select>
|
||||||
|
<span class="help-block">Alter this if your business sector has changed.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>City/Town Location</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="text" class="form-control" formControlName="town">
|
||||||
|
<span class="help-block">Change this if the city or town your business is located at has changed.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-block">
|
||||||
|
<div [ngSwitch]="submitStatus">
|
||||||
|
<div *ngSwitchCase="'success'" class="alert alert-success" role="alert">
|
||||||
|
Account Update Succeeded.
|
||||||
|
</div>
|
||||||
|
<div *ngSwitchCase="'validation_failed'" class="alert alert-danger" role="alert">
|
||||||
|
Form validation failed, please ensure the form is filled correctly.
|
||||||
|
</div>
|
||||||
|
<div *ngSwitchCase="'send_failed'" class="alert alert-danger" role="alert">
|
||||||
|
Failed to send to server, please try again later.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<button type="submit" class="btn btn-sm btn-primary"><i class="fa fa-dot-circle-o"></i> Submit</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div *ngSwitchCase="'customer'">
|
||||||
|
<form class="form-horizontal" [formGroup]="settingCustomerForm" (ngSubmit)="onSubmitCustomer()">
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Full Name</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="text" class="form-control" formControlName="full_name">
|
||||||
|
<span class="help-block">Change this if your full name has changed.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Display Name</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="text" class="form-control" formControlName="display_name">
|
||||||
|
<span class="help-block">Change this if wish to alter your user display name.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-block">
|
||||||
|
<div [ngSwitch]="submitStatus">
|
||||||
|
<div *ngSwitchCase="'success'" class="alert alert-success" role="alert">
|
||||||
|
Account Update Succeeded.
|
||||||
|
</div>
|
||||||
|
<div *ngSwitchCase="'validation_failed'" class="alert alert-danger" role="alert">
|
||||||
|
Form validation failed, please ensure the form is filled correctly.
|
||||||
|
</div>
|
||||||
|
<div *ngSwitchCase="'send_failed'" class="alert alert-danger" role="alert">
|
||||||
|
Failed to send to server, please try again later.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<button type="submit" class="btn btn-sm btn-primary"><i class="fa fa-dot-circle-o"></i> Submit</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!--/.row-->
|
||||||
|
</div>
|
169
src/app/dashboard/account-edit.component.ts
Normal file
169
src/app/dashboard/account-edit.component.ts
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
|
import { Validators, FormBuilder, FormGroup } from '@angular/forms';
|
||||||
|
import { Http, Response } from '@angular/http';
|
||||||
|
import { ApiService } from '../providers/api-service';
|
||||||
|
import 'rxjs/add/operator/map';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: 'account-edit.component.html',
|
||||||
|
})
|
||||||
|
export class AccountEditComponent implements OnInit {
|
||||||
|
settingForm: FormGroup;
|
||||||
|
settingOrganisationForm: FormGroup;
|
||||||
|
settingCustomerForm: FormGroup;
|
||||||
|
accountType: any;
|
||||||
|
// @ViewChild('fileInput') fileInput;
|
||||||
|
submitStatus: any;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private http: Http,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private api: ApiService,
|
||||||
|
) {
|
||||||
|
this.settingForm = this.formBuilder.group({
|
||||||
|
email : ['', [Validators.required]],
|
||||||
|
postcode : ['', [Validators.required]],
|
||||||
|
password : ['', [Validators.required]],
|
||||||
|
new_password : [''],
|
||||||
|
});
|
||||||
|
this.settingOrganisationForm = this.formBuilder.group({
|
||||||
|
name : ['', [Validators.required]],
|
||||||
|
street_name : ['', [Validators.required]],
|
||||||
|
town : ['', [Validators.required]],
|
||||||
|
sector : ['', [Validators.required]],
|
||||||
|
});
|
||||||
|
this.settingCustomerForm = this.formBuilder.group({
|
||||||
|
full_name : ['', [Validators.required]],
|
||||||
|
display_name : ['', [Validators.required]],
|
||||||
|
});
|
||||||
|
this.accountType = localStorage.getItem('usertype');
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.api.accountFullLoad().subscribe(
|
||||||
|
result => {
|
||||||
|
console.log(result);
|
||||||
|
this.settingForm.patchValue({
|
||||||
|
email: result.email,
|
||||||
|
postcode: result.postcode,
|
||||||
|
password: '',
|
||||||
|
new_password: '',
|
||||||
|
});
|
||||||
|
this.settingOrganisationForm.patchValue({
|
||||||
|
name: result.name,
|
||||||
|
street_name: result.street_name,
|
||||||
|
town: result.town,
|
||||||
|
sector: result.sector,
|
||||||
|
});
|
||||||
|
this.settingCustomerForm.patchValue({
|
||||||
|
full_name: result.full_name,
|
||||||
|
display_name: result.display_name,
|
||||||
|
});
|
||||||
|
this.api.setUserInfo( result.email, result.display_name || result.name );
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log( error._body );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmitOrganisation() {
|
||||||
|
console.log(this.settingForm.valid);
|
||||||
|
if (!this.settingForm.valid && !this.settingOrganisationForm.valid) {
|
||||||
|
console.log('Not Valid!');
|
||||||
|
this.submitStatus = "validation_failed";
|
||||||
|
console.log(this.submitStatus);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const settingForm = this.settingForm.value;
|
||||||
|
const settingOrganisationForm = this.settingOrganisationForm.value;
|
||||||
|
|
||||||
|
// image upload code
|
||||||
|
// const fi = this.fileInput.nativeElement;
|
||||||
|
// const data = new FormData();
|
||||||
|
|
||||||
|
// if (fi.files && fi.files[0]) {
|
||||||
|
// const fileToUpload = fi.files[0];
|
||||||
|
// data.append('file', fileToUpload);
|
||||||
|
// }
|
||||||
|
|
||||||
|
const submitData = {
|
||||||
|
email: settingForm.email,
|
||||||
|
postcode: settingForm.postcode,
|
||||||
|
password: settingForm.password,
|
||||||
|
new_password: settingForm.new_password,
|
||||||
|
name: settingOrganisationForm.name,
|
||||||
|
street_name: settingOrganisationForm.street_name,
|
||||||
|
town: settingOrganisationForm.town,
|
||||||
|
sector: settingOrganisationForm.sector,
|
||||||
|
};
|
||||||
|
|
||||||
|
// data.append('form', JSON.stringify(submitData));
|
||||||
|
|
||||||
|
console.log(submitData);
|
||||||
|
this.api
|
||||||
|
.accountEditUpdate(submitData)
|
||||||
|
.subscribe(
|
||||||
|
result => {
|
||||||
|
console.log('data submitted!');
|
||||||
|
this.submitStatus = "success";
|
||||||
|
console.log(this.submitStatus);
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log( error._body );
|
||||||
|
this.submitStatus = "send_failed";
|
||||||
|
console.log(this.submitStatus);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmitCustomer() {
|
||||||
|
console.log(this.settingForm.valid);
|
||||||
|
if (!this.settingForm.valid && !this.settingCustomerForm.valid) {
|
||||||
|
console.log('Not Valid!');
|
||||||
|
this.submitStatus = "validation_failed";
|
||||||
|
console.log(this.submitStatus);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const settingForm = this.settingForm.value;
|
||||||
|
const settingCustomerForm = this.settingCustomerForm.value;
|
||||||
|
|
||||||
|
// image upload code
|
||||||
|
// const fi = this.fileInput.nativeElement;
|
||||||
|
const data = new FormData();
|
||||||
|
|
||||||
|
// if (fi.files && fi.files[0]) {
|
||||||
|
// const fileToUpload = fi.files[0];
|
||||||
|
// data.append('file', fileToUpload);
|
||||||
|
// }
|
||||||
|
|
||||||
|
const submitData = {
|
||||||
|
email: settingForm.email,
|
||||||
|
postcode: settingForm.postcode,
|
||||||
|
password: settingForm.password,
|
||||||
|
new_password: settingForm.new_password,
|
||||||
|
full_name: settingCustomerForm.full_name,
|
||||||
|
display_name: settingCustomerForm.display_name,
|
||||||
|
};
|
||||||
|
|
||||||
|
// data.append('form', JSON.stringify(submitData));
|
||||||
|
|
||||||
|
this.api
|
||||||
|
.accountEditUpdate(submitData)
|
||||||
|
.subscribe(
|
||||||
|
result => {
|
||||||
|
console.log('data submitted!');
|
||||||
|
this.submitStatus = "success";
|
||||||
|
console.log(this.submitStatus);
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log( error._body );
|
||||||
|
this.submitStatus = "send_failed";
|
||||||
|
console.log(this.submitStatus);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
272
src/app/dashboard/add-data.component.html
Normal file
272
src/app/dashboard/add-data.component.html
Normal file
|
@ -0,0 +1,272 @@
|
||||||
|
<div class="animated fadeIn">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<strong>Submit Transaction</strong>
|
||||||
|
<small>Required Data marked in <strong>bold</strong>.</small>
|
||||||
|
</div>
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Time of Transaction</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="datetime-local" class="form-control" [min]="minDate" [(ngModel)]="myDate" (ngModelChange)="transactionFormValidate()">
|
||||||
|
<span class="help-block">Enter the date and time the transaction occurred.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Amount</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon"><i class="fa fa-gbp"></i></span>
|
||||||
|
<input type="number" min="0.00" step="0.01" class="form-control" placeholder="0.00" [(ngModel)]="amount" (ngModelChange)="transactionFormValidate()">
|
||||||
|
</div>
|
||||||
|
<span class="help-block">Enter the amount spent, such as 5.35 for £5.35.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Organisation Name</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="text" class="form-control" placeholder="Organisation Name" [(ngModel)]="submitOrg.name" (input)="organisationSearch($event)" (ngModelChange)="transactionFormValidate()">
|
||||||
|
<span class="help-block">Enter the name of the organisation money was spent. Choose existing ones from below or if not found, enter the details below.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<org-table *ngIf="storeList != null" [orgList]="storeList" (onClick)="addStore($event)"></org-table>
|
||||||
|
<div *ngIf="showAddStore">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Organisation Street Name</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="text" class="form-control" placeholder="Which Street?" [(ngModel)]="submitOrg.street_name" (ngModelChange)="transactionFormValidate()">
|
||||||
|
<span class="help-block">Enter the street name where the organisation is located at.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Organisation Town</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="text" class="form-control" placeholder="Which Town?" [(ngModel)]="submitOrg.town" (ngModelChange)="transactionFormValidate()">
|
||||||
|
<span class="help-block">Enter the name of the town where the organisation is located at.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Organisation Postcode</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="text" class="form-control" placeholder="Postcode if known" [(ngModel)]="submitOrg.postcode" (ngModelChange)="transactionFormValidate()">
|
||||||
|
<span class="help-block">Enter the postcode where the organisation is located at.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col-md-9">
|
||||||
|
<div [ngSwitch]="transactionFormStatus">
|
||||||
|
<div *ngSwitchCase="'success'" class="alert alert-success" role="alert">
|
||||||
|
Submit Succeeded.
|
||||||
|
</div>
|
||||||
|
<div *ngSwitchCase="'send_failed'" class="alert alert-danger" role="alert">
|
||||||
|
{{transactionFormStatusError}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<button type="submit" (click)="postTransaction()" [disabled]="transactionFormInvalid" class="btn btn-sm btn-primary"><i class="fa fa-dot-circle-o"></i> Submit</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="false" class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<strong>Profile & Payroll Data</strong>
|
||||||
|
<small>Required Data marked in <strong>bold</strong>.</small>
|
||||||
|
</div>
|
||||||
|
<form class="form-horizontal" [formGroup]="payrollForm" (ngSubmit)="onSubmitPayroll()">
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Period of entry month</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="month" class="form-control" formControlName="entry_period">
|
||||||
|
<span class="help-block">Enter the month and year for this information.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Total amount of Employees</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="number" class="form-control" formControlName="employee_amount" placeholder="0">
|
||||||
|
<span class="help-block">Enter the amount of employees the organisation has for the entry month.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Total amount of local Employees</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="number" class="form-control" formControlName="local_employee_amount" placeholder="0">
|
||||||
|
<span class="help-block">Enter the amount of employees that live locally to the organisation for the entry month.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Gross Payroll</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon"><i class="fa fa-gbp"></i></span>
|
||||||
|
<input type="number" min="0.00" step="0.01" class="form-control" formControlName="gross_payroll" placeholder="0.00">
|
||||||
|
</div>
|
||||||
|
<span class="help-block">Enter the Gross Payroll for the organisation for the entry month.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Total Income Tax</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon"><i class="fa fa-gbp"></i></span>
|
||||||
|
<input type="number" min="0.00" step="0.01" class="form-control" formControlName="payroll_income_tax" placeholder="0.00">
|
||||||
|
</div>
|
||||||
|
<span class="help-block">Enter the organisation's total income tax for the entry month.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Employees Total NI</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon"><i class="fa fa-gbp"></i></span>
|
||||||
|
<input type="number" min="0.00" step="0.01" class="form-control" formControlName="payroll_employee_ni" placeholder="0.00">
|
||||||
|
</div>
|
||||||
|
<span class="help-block">Total of Employees National Insurance contributions for the entry month</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Employers Total NI</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon"><i class="fa fa-gbp"></i></span>
|
||||||
|
<input type="number" min="0.00" step="0.01" class="form-control" formControlName="payroll_employer_ni" placeholder="0.00">
|
||||||
|
</div>
|
||||||
|
<span class="help-block">Employers National Insurance contributions for the entry month</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Total Pensions</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon"><i class="fa fa-gbp"></i></span>
|
||||||
|
<input type="number" min="0.00" step="0.01" class="form-control" formControlName="payroll_total_pension" placeholder="0.00">
|
||||||
|
</div>
|
||||||
|
<span class="help-block">Total spent on employee pensions by the organisation for the entry month</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Total Other Benefits</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon"><i class="fa fa-gbp"></i></span>
|
||||||
|
<input type="number" min="0.00" step="0.01" class="form-control" formControlName="payroll_other_benefit" placeholder="0.00">
|
||||||
|
</div>
|
||||||
|
<span class="help-block">A total of other payments such as refunded fuel etc. for the entry month</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col-md-9">
|
||||||
|
<div [ngSwitch]="payrollFormStatus">
|
||||||
|
<div *ngSwitchCase="'success'" class="alert alert-success" role="alert">
|
||||||
|
Submit Succeeded.
|
||||||
|
</div>
|
||||||
|
<div *ngSwitchCase="'send_failed'" class="alert alert-danger" role="alert">
|
||||||
|
Error received, please try again.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<button type="submit" [disabled]="!payrollForm.valid" class="btn btn-sm btn-primary"><i class="fa fa-dot-circle-o"></i> Submit</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="false" class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<strong>Individual Employee Data</strong>
|
||||||
|
<small>Required Data marked in <strong>bold</strong>.</small>
|
||||||
|
</div>
|
||||||
|
<form class="form-horizontal" [formGroup]="employeeForm" (ngSubmit)="onSubmitEmployee()">
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Period of entry month</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="month" class="form-control" formControlName="entry_period">
|
||||||
|
<span class="help-block">Enter the month and year for this information.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Employee number</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="number" class="form-control" formControlName="employee_no" placeholder="0">
|
||||||
|
<span class="help-block">Used to identify employee anonymously</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Gross Wage</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon"><i class="fa fa-gbp"></i></span>
|
||||||
|
<input type="number" min="0.00" step="0.01" class="form-control" formControlName="employee_gross_wage" placeholder="0.00">
|
||||||
|
</div>
|
||||||
|
<span class="help-block">Enter the gross wage of the employee for the entry month.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Total Income Tax</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon"><i class="fa fa-gbp"></i></span>
|
||||||
|
<input type="number" min="0.00" step="0.01" class="form-control" formControlName="employee_income_tax" placeholder="0.00">
|
||||||
|
</div>
|
||||||
|
<span class="help-block">Enter the total income tax of the employee for the entry month</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Total Employee NI</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon"><i class="fa fa-gbp"></i></span>
|
||||||
|
<input type="number" min="0.00" step="0.01" class="form-control" formControlName="employee_ni" placeholder="0.00">
|
||||||
|
</div>
|
||||||
|
<span class="help-block">Individual Employees National Insurance Contributions for the entry month</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Employee's Pension</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon"><i class="fa fa-gbp"></i></span>
|
||||||
|
<input type="number" min="0.00" step="0.01" class="form-control" formControlName="employee_pension" placeholder="0.00">
|
||||||
|
</div>
|
||||||
|
<span class="help-block">Individual Employees Pension contributions for the entry month</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Total Employee Other Benefits</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon"><i class="fa fa-gbp"></i></span>
|
||||||
|
<input type="number" min="0.00" step="0.01" class="form-control" formControlName="employee_other_benefit" placeholder="0.00">
|
||||||
|
</div>
|
||||||
|
<span class="help-block">A total of other payments such as refunded fuel etc. for the entry month</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col-md-9">
|
||||||
|
<div [ngSwitch]="employeeFormStatus">
|
||||||
|
<div *ngSwitchCase="'success'" class="alert alert-success" role="alert">
|
||||||
|
Submit Succeeded.
|
||||||
|
</div>
|
||||||
|
<div *ngSwitchCase="'send_failed'" class="alert alert-danger" role="alert">
|
||||||
|
Error received, please try again.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<button type="submit" [disabled]="!employeeForm.valid" class="btn btn-sm btn-primary"><i class="fa fa-dot-circle-o"></i> Submit</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!--/.row-->
|
||||||
|
</div>
|
301
src/app/dashboard/add-data.component.ts
Normal file
301
src/app/dashboard/add-data.component.ts
Normal file
|
@ -0,0 +1,301 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Validators, FormBuilder, FormGroup } from '@angular/forms';
|
||||||
|
import { Http, Response } from '@angular/http';
|
||||||
|
import { ApiService } from '../providers/api-service';
|
||||||
|
import { OrgTableComponent } from '../shared/org-table.component';
|
||||||
|
import * as moment from 'moment';
|
||||||
|
import 'rxjs/add/operator/map';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: 'add-data.component.html',
|
||||||
|
})
|
||||||
|
export class AddDataComponent {
|
||||||
|
payrollForm: FormGroup;
|
||||||
|
singleSupplierForm: FormGroup;
|
||||||
|
employeeForm: FormGroup;
|
||||||
|
transactionForm: FormGroup;
|
||||||
|
payrollFormStatus: any;
|
||||||
|
singleSupplierFormStatus: any;
|
||||||
|
employeeFormStatus: any;
|
||||||
|
transactionFormStatus: any;
|
||||||
|
transactionFormStatusError: string = 'Error received, please try again.';
|
||||||
|
accountType: any;
|
||||||
|
|
||||||
|
submitOrg = {
|
||||||
|
name: '',
|
||||||
|
street_name: '',
|
||||||
|
town: '',
|
||||||
|
postcode: '',
|
||||||
|
};
|
||||||
|
organisationId: number;
|
||||||
|
organisationTown: string;
|
||||||
|
organisationPostcode: string;
|
||||||
|
amount: number;
|
||||||
|
transactionAdditionType = 1;
|
||||||
|
storeList;
|
||||||
|
showAddStore = false;
|
||||||
|
submitReceipt = false;
|
||||||
|
transactionFormInvalid = true;
|
||||||
|
myDate: any;
|
||||||
|
minDate: any;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private http: Http,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private api: ApiService,
|
||||||
|
) {
|
||||||
|
this.payrollForm = this.formBuilder.group({
|
||||||
|
entry_period: ['', [Validators.required]],
|
||||||
|
employee_amount: ['', [Validators.required]],
|
||||||
|
local_employee_amount: ['', [Validators.required]],
|
||||||
|
gross_payroll: ['', [Validators.required]],
|
||||||
|
payroll_income_tax: ['', [Validators.required]],
|
||||||
|
payroll_employee_ni: ['', [Validators.required]],
|
||||||
|
payroll_employer_ni: ['', [Validators.required]],
|
||||||
|
payroll_total_pension: ['', [Validators.required]],
|
||||||
|
payroll_other_benefit: ['', [Validators.required]],
|
||||||
|
});
|
||||||
|
this.employeeForm = this.formBuilder.group({
|
||||||
|
entry_period: ['', [Validators.required]],
|
||||||
|
employee_no: ['', [Validators.required]],
|
||||||
|
employee_income_tax: ['', [Validators.required]],
|
||||||
|
employee_gross_wage: ['', [Validators.required]],
|
||||||
|
employee_ni: ['', [Validators.required]],
|
||||||
|
employee_pension: ['', [Validators.required]],
|
||||||
|
employee_other_benefit: ['', [Validators.required]],
|
||||||
|
});
|
||||||
|
this.myDate = moment().format('YYYY-MM-DD[T]HH:mm');
|
||||||
|
// this.myDate = new Date().toISOString().slice(0, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.getMinDate();
|
||||||
|
this.accountType = localStorage.getItem('usertype');
|
||||||
|
}
|
||||||
|
|
||||||
|
getMinDate(){
|
||||||
|
// gets the April 1st date of the current year
|
||||||
|
let aprilDate = moment().month(3).date(1);
|
||||||
|
let now = moment();
|
||||||
|
// Checks if current time is before April 1st, if so returns true
|
||||||
|
let beforeApril = now.isBefore(aprilDate);
|
||||||
|
if ( beforeApril == true ) {
|
||||||
|
this.minDate = aprilDate.subtract(2, 'years').format('YYYY-MM-DD');
|
||||||
|
} else {
|
||||||
|
this.minDate = aprilDate.subtract(1, 'years').format('YYYY-MM-DD');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeItems() {
|
||||||
|
// Dont bother searching for an empty or undefined string
|
||||||
|
if ( this.submitOrg.name == '' ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var searchData = {
|
||||||
|
search_name: this.submitOrg.name,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.api.search(searchData).subscribe(
|
||||||
|
data => {
|
||||||
|
if(data.validated.length > 0) {
|
||||||
|
this.storeList = data.validated;
|
||||||
|
this.showAddStore = false;
|
||||||
|
this.transactionAdditionType = 1;
|
||||||
|
} else {
|
||||||
|
this.storeList = data.unvalidated;
|
||||||
|
this.showAddStore = false;
|
||||||
|
this.transactionAdditionType = 2;
|
||||||
|
}
|
||||||
|
// handle the case when the storelist is empty
|
||||||
|
if(this.storeList.length < 1 ) {
|
||||||
|
this.storeList = null;
|
||||||
|
this.showAddStore = true;
|
||||||
|
this.transactionAdditionType = 3;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if user select a item from the list
|
||||||
|
addStore(store){
|
||||||
|
this.submitOrg = store;
|
||||||
|
this.transactionFormValidate();
|
||||||
|
this.organisationId = store.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// search for store
|
||||||
|
organisationSearch(ev) {
|
||||||
|
// Reset items back to all of the items
|
||||||
|
this.initializeItems();
|
||||||
|
|
||||||
|
// set val to the value of the searchbar
|
||||||
|
let val = ev.target.value;
|
||||||
|
|
||||||
|
// Filter the store list so search seems quicker
|
||||||
|
if (val && val.trim() != '' && this.storeList != null) {
|
||||||
|
this.storeList = this.storeList.filter(
|
||||||
|
(item) => {
|
||||||
|
return ( item.name.toLowerCase().indexOf( val.toLowerCase() ) > -1 );
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// if nothing is found
|
||||||
|
if(!this.storeList === null){
|
||||||
|
// display add new store button
|
||||||
|
this.showAddStore = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transactionFormValidate() {
|
||||||
|
if( this.submitOrg.name.length == 0 &&
|
||||||
|
this.amount == 0 ) {
|
||||||
|
this.transactionFormInvalid = true;
|
||||||
|
}else{
|
||||||
|
this.transactionFormInvalid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public postTransaction() {
|
||||||
|
|
||||||
|
var myParams: any;
|
||||||
|
let purchaseTime: string;
|
||||||
|
purchaseTime = moment(this.myDate, 'YYYY-MM-DD[T]HH:mm').local().format('YYYY-MM-DD[T]HH:mm:ss.SSSZ');
|
||||||
|
switch(this.transactionAdditionType){
|
||||||
|
case 1:
|
||||||
|
myParams = {
|
||||||
|
transaction_type : this.transactionAdditionType,
|
||||||
|
transaction_value : this.amount,
|
||||||
|
purchase_time : purchaseTime,
|
||||||
|
organisation_id : this.organisationId,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
myParams = {
|
||||||
|
transaction_type : this.transactionAdditionType,
|
||||||
|
transaction_value : this.amount,
|
||||||
|
purchase_time : purchaseTime,
|
||||||
|
organisation_id : this.organisationId,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
myParams = {
|
||||||
|
transaction_type : this.transactionAdditionType,
|
||||||
|
transaction_value : this.amount,
|
||||||
|
purchase_time : purchaseTime,
|
||||||
|
organisation_name : this.submitOrg.name,
|
||||||
|
street_name : this.submitOrg.street_name,
|
||||||
|
town : this.submitOrg.town,
|
||||||
|
postcode : this.submitOrg.postcode,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/******************************/
|
||||||
|
|
||||||
|
this.api
|
||||||
|
.upload(myParams)
|
||||||
|
.subscribe(
|
||||||
|
result => {
|
||||||
|
if ( result.success == true ) {
|
||||||
|
console.log('Successful Upload');
|
||||||
|
console.log(result);
|
||||||
|
this.transactionFormStatus = "success";
|
||||||
|
console.log(this.transactionFormStatus);
|
||||||
|
this.resetForm();
|
||||||
|
} else {
|
||||||
|
console.log('Upload Error');
|
||||||
|
this.transactionFormStatusError = JSON.stringify(result.status) + 'Error, ' + JSON.stringify(result.message);
|
||||||
|
this.transactionFormStatus = "send_failed";
|
||||||
|
console.log(this.transactionFormStatus);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log('Upload Error');
|
||||||
|
console.log(error);
|
||||||
|
try {
|
||||||
|
console.log(error.error);
|
||||||
|
let jsonError = error.json();
|
||||||
|
console.log("boop");
|
||||||
|
this.transactionFormStatusError = '"' + jsonError.error + '" Error, ' + jsonError.message;
|
||||||
|
} catch(e) {
|
||||||
|
this.transactionFormStatusError = 'There was a server error, please try again later.';
|
||||||
|
}
|
||||||
|
this.transactionFormStatus = "send_failed";
|
||||||
|
console.log(this.transactionFormStatus);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private resetForm() {
|
||||||
|
this.submitOrg = {
|
||||||
|
name: '',
|
||||||
|
street_name: '',
|
||||||
|
town: '',
|
||||||
|
postcode: '',
|
||||||
|
};
|
||||||
|
this.storeList = null;
|
||||||
|
this.amount = null;
|
||||||
|
this.transactionFormInvalid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmitPayroll() {
|
||||||
|
console.log(this.payrollForm.value);
|
||||||
|
|
||||||
|
this.api
|
||||||
|
.orgPayroll(this.payrollForm.value)
|
||||||
|
.subscribe(
|
||||||
|
result => {
|
||||||
|
console.log('data submitted!');
|
||||||
|
this.payrollFormStatus = "success";
|
||||||
|
console.log(this.payrollFormStatus);
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log( error._body );
|
||||||
|
this.payrollFormStatus = "send_failed";
|
||||||
|
console.log(this.payrollFormStatus);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmitSingleSupplier() {
|
||||||
|
console.log(this.singleSupplierForm.value);
|
||||||
|
|
||||||
|
this.api
|
||||||
|
.orgSupplier(this.singleSupplierForm.value)
|
||||||
|
.subscribe(
|
||||||
|
result => {
|
||||||
|
console.log('data submitted!');
|
||||||
|
this.singleSupplierFormStatus = "success";
|
||||||
|
console.log(this.singleSupplierFormStatus);
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log( error._body );
|
||||||
|
this.singleSupplierFormStatus = "send_failed";
|
||||||
|
console.log(this.singleSupplierFormStatus);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmitEmployee() {
|
||||||
|
console.log(this.employeeForm.value);
|
||||||
|
|
||||||
|
this.api
|
||||||
|
.orgEmployee(this.employeeForm.value)
|
||||||
|
.subscribe(
|
||||||
|
result => {
|
||||||
|
console.log('data submitted!');
|
||||||
|
this.employeeFormStatus = "success";
|
||||||
|
console.log(this.employeeFormStatus);
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log( error._body );
|
||||||
|
this.employeeFormStatus = "send_failed";
|
||||||
|
console.log(this.employeeFormStatus);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
131
src/app/dashboard/dashboard-customer.component.html
Normal file
131
src/app/dashboard/dashboard-customer.component.html
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
<div class="animated fadeIn">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-footer">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<div class="text-muted">My Points</div>
|
||||||
|
<strong>{{ basicStats.user_sum / 10 | number:'1.0-0' }}</strong>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="text-muted">My Rank</div>
|
||||||
|
<div *ngIf="basicStats.user_position == 0" class="statuscontent">
|
||||||
|
<strong>Unranked</strong>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="basicStats.user_position != 0" class="statuscontent">
|
||||||
|
<strong>{{ basicStats.user_position }}</strong>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<div class="text-muted">My Total Spend</div>
|
||||||
|
<strong>{{ basicStats.user_sum | currency:'GBP':true:'1.2-2' }}</strong>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="text-muted">Value to Local Economy</div>
|
||||||
|
<strong>{{ basicStats.user_sum * 2.3 | currency:'GBP':true:'1.2-2' }}</strong>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-6 col-lg-3">
|
||||||
|
<div class="card card-inverse card-primary">
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="h4 mb-0">{{ basicStats.today_sum | currency:'GBP':true:'1.2-2' }}</div>
|
||||||
|
<div>Total Today</div>
|
||||||
|
<!-- <div class="progress progress-white progress-xs mt-3">
|
||||||
|
<div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
|
||||||
|
</div>
|
||||||
|
<small class="text-muted">Lorem ipsum dolor sit amet enim.</small> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!--/.col-->
|
||||||
|
<div class="col-sm-6 col-lg-3">
|
||||||
|
<div class="card card-inverse card-primary">
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="h4 mb-0">{{ basicStats.today_sum / (basicStats.today_count ? basicStats.today_count : 1) | currency:'GBP':true:'1.2-2' }}</div>
|
||||||
|
<div>Avg. Spend Today</div>
|
||||||
|
<!-- <div class="progress progress-white progress-xs mt-3">
|
||||||
|
<div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
|
||||||
|
</div>
|
||||||
|
<small class="text-muted">Lorem ipsum dolor sit amet enim.</small> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!--/.col-->
|
||||||
|
<div class="col-sm-6 col-lg-3">
|
||||||
|
<div class="card card-inverse card-primary">
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="h4 mb-0">{{ basicStats.week_sum | currency:'GBP':true:'1.2-2' }}</div>
|
||||||
|
<div>Last Week Total</div>
|
||||||
|
<!-- <div class="progress progress-white progress-xs mt-3">
|
||||||
|
<div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
|
||||||
|
</div>
|
||||||
|
<small class="text-muted">Lorem ipsum dolor sit amet enim.</small> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!--/.col-->
|
||||||
|
<div class="col-sm-6 col-lg-3">
|
||||||
|
<div class="card card-inverse card-primary">
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="h4 mb-0">{{ basicStats.week_sum / (basicStats.week_count ? basicStats.week_count : 1) | currency:'GBP':true:'1.2-2' }}</div>
|
||||||
|
<div>Last Week Avg. Spend</div>
|
||||||
|
<!-- <div class="progress progress-white progress-xs mt-3">
|
||||||
|
<div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
|
||||||
|
</div>
|
||||||
|
<small class="text-muted">Lorem ipsum dolor sit amet enim.</small> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!--/.col-->
|
||||||
|
<div class="col-sm-6 col-lg-3">
|
||||||
|
<div class="card card-inverse card-primary">
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="h4 mb-0">{{ basicStats.month_sum | currency:'GBP':true:'1.2-2' }}</div>
|
||||||
|
<div>Last Month Total</div>
|
||||||
|
<!-- <div class="progress progress-white progress-xs mt-3">
|
||||||
|
<div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
|
||||||
|
</div>
|
||||||
|
<small class="text-muted">Lorem ipsum dolor sit amet enim.</small> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!--/.col-->
|
||||||
|
<div class="col-sm-6 col-lg-3">
|
||||||
|
<div class="card card-inverse card-primary">
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="h4 mb-0">{{ basicStats.month_sum / (basicStats.month_count ? basicStats.month_count : 1) | currency:'GBP':true:'1.2-2' }}</div>
|
||||||
|
<div>Last Month Avg. Spend</div>
|
||||||
|
<!-- <div class="progress progress-white progress-xs mt-3">
|
||||||
|
<div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
|
||||||
|
</div>
|
||||||
|
<small class="text-muted">Lorem ipsum dolor sit amet enim.</small> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!--/.col-->
|
||||||
|
<div class="col-sm-6 col-lg-3">
|
||||||
|
<div class="card card-inverse card-primary">
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="h4 mb-0">{{ basicStats.user_sum | currency:'GBP':true:'1.2-2' }}</div>
|
||||||
|
<div>User Total</div>
|
||||||
|
<!-- <div class="progress progress-white progress-xs mt-3">
|
||||||
|
<div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
|
||||||
|
</div>
|
||||||
|
<small class="text-muted">Lorem ipsum dolor sit amet enim.</small> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!--/.col-->
|
||||||
|
<div class="col-sm-6 col-lg-3">
|
||||||
|
<div class="card card-inverse card-primary">
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="h4 mb-0">{{ basicStats.user_sum / (basicStats.user_count ? basicStats.user_count : 1) | currency:'GBP':true:'1.2-2' }}</div>
|
||||||
|
<div>User Avg. Spend</div>
|
||||||
|
<!-- <div class="progress progress-white progress-xs mt-3">
|
||||||
|
<div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
|
||||||
|
</div>
|
||||||
|
<small class="text-muted">Lorem ipsum dolor sit amet enim.</small> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!--/.col-->
|
||||||
|
</div><!--/.row-->
|
||||||
|
</div>
|
55
src/app/dashboard/dashboard-customer.component.ts
Normal file
55
src/app/dashboard/dashboard-customer.component.ts
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
import { Directive, Component, OnInit } from '@angular/core';
|
||||||
|
import { Http, Response } from '@angular/http';
|
||||||
|
import { ApiService } from '../providers/api-service';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { GraphWidget } from '../widgets/graph-widget.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: 'dashboard-customer.component.html'
|
||||||
|
})
|
||||||
|
export class DashboardCustomerComponent implements OnInit {
|
||||||
|
customersThisMonth: any;
|
||||||
|
moneySpentThisMonth: any;
|
||||||
|
pointsTotal: any;
|
||||||
|
averageTransactionToday: any;
|
||||||
|
|
||||||
|
/* Setting up dashboard's main variables*/
|
||||||
|
name: any;
|
||||||
|
email:any;
|
||||||
|
myPearPoints: any;
|
||||||
|
trends: any;
|
||||||
|
myRank: any;
|
||||||
|
username: any;
|
||||||
|
|
||||||
|
basicStats = {
|
||||||
|
today_sum: 0,
|
||||||
|
today_count: 0,
|
||||||
|
week_sum: 0,
|
||||||
|
week_count: 0,
|
||||||
|
month_sum: 0,
|
||||||
|
month_count: 0,
|
||||||
|
user_sum: 0,
|
||||||
|
user_count: 0,
|
||||||
|
global_sum: 0,
|
||||||
|
global_count: 0,
|
||||||
|
user_position: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private http: Http,
|
||||||
|
private api: ApiService,
|
||||||
|
) {
|
||||||
|
this.api.basicStats().subscribe(
|
||||||
|
result => {
|
||||||
|
this.basicStats = result;
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log('Retrieval Error');
|
||||||
|
console.log( error._body );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
}
|
13
src/app/dashboard/dashboard.component.html
Normal file
13
src/app/dashboard/dashboard.component.html
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<div class="animated fadeIn">
|
||||||
|
<snippet-bar-org></snippet-bar-org>
|
||||||
|
<div class="row">
|
||||||
|
<div *ngFor="let widget of widgetList" class="col-sm-6 col-lg-3">
|
||||||
|
<widget-graph *ngIf="widget.type == 'graph'"
|
||||||
|
[graphName]="widget.name"
|
||||||
|
[graphTitle]="widget.title"
|
||||||
|
[graphIcon]="widget.icon"
|
||||||
|
[dataType]="widget.dataType"></widget-graph>
|
||||||
|
</div><!--/.col-->
|
||||||
|
</div><!--/.row-->
|
||||||
|
<panel-graph></panel-graph>
|
||||||
|
</div>
|
55
src/app/dashboard/dashboard.component.ts
Normal file
55
src/app/dashboard/dashboard.component.ts
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { GraphWidget } from '../widgets/graph-widget.component';
|
||||||
|
import { OrgBarSnippetComponent } from '../snippets/org-snippet-bar.component';
|
||||||
|
import { GraphPanel } from '../panels/graph-panel.component';
|
||||||
|
import { DataType } from '../shared/data-types.enum';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: 'dashboard.component.html'
|
||||||
|
})
|
||||||
|
export class DashboardComponent {
|
||||||
|
|
||||||
|
public widgetList = [
|
||||||
|
{
|
||||||
|
type: 'graph',
|
||||||
|
name: 'customers_last_7_days',
|
||||||
|
icon: 'icon-people',
|
||||||
|
title: 'Customers Last 7 Days',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'graph',
|
||||||
|
name: 'customers_last_30_days',
|
||||||
|
icon: 'icon-people',
|
||||||
|
title: 'Customers Last 30 Days',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'graph',
|
||||||
|
name: 'sales_last_7_days',
|
||||||
|
icon: 'icon-diamond',
|
||||||
|
title: 'Sales Last 7 Days',
|
||||||
|
dataType: DataType.currency,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'graph',
|
||||||
|
name: 'sales_last_30_days',
|
||||||
|
icon: 'icon-diamond',
|
||||||
|
title: 'Sales Last 30 Days',
|
||||||
|
dataType: DataType.currency,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'graph',
|
||||||
|
name: 'purchases_last_7_days',
|
||||||
|
title: 'Purchases Last 7 Days',
|
||||||
|
dataType: DataType.currency,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'graph',
|
||||||
|
name: 'purchases_last_30_days',
|
||||||
|
title: 'Purchases Last 30 Days',
|
||||||
|
dataType: DataType.currency,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
}
|
55
src/app/dashboard/dashboard.module.ts
Normal file
55
src/app/dashboard/dashboard.module.ts
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { ChartsModule } from 'ng2-charts/ng2-charts';
|
||||||
|
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
|
||||||
|
import { NgxPaginationModule } from 'ngx-pagination';
|
||||||
|
|
||||||
|
import { CurrencyPipe } from '@angular/common';
|
||||||
|
|
||||||
|
import { DashboardComponent } from './dashboard.component';
|
||||||
|
import { DashboardCustomerComponent } from './dashboard-customer.component';
|
||||||
|
import { AccountEditComponent } from './account-edit.component';
|
||||||
|
import { AddDataComponent } from './add-data.component';
|
||||||
|
import { FeedbackComponent } from './feedback.component';
|
||||||
|
import { TransactionLogComponent } from './transaction-log.component';
|
||||||
|
|
||||||
|
import { GraphWidget } from '../widgets/graph-widget.component';
|
||||||
|
import { OrgBarSnippetComponent } from '../snippets/org-snippet-bar.component';
|
||||||
|
import { GraphPanel } from '../panels/graph-panel.component';
|
||||||
|
|
||||||
|
import { DashboardRoutingModule } from './dashboard.routing';
|
||||||
|
import { OrgResultComponent } from '../shared/org-result.component';
|
||||||
|
import { OrgTableComponent } from '../shared/org-table.component';
|
||||||
|
import { TransactionResultComponent } from '../shared/transaction-result.component';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
// Angular imports
|
||||||
|
CommonModule,
|
||||||
|
FormsModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
ChartsModule,
|
||||||
|
BsDropdownModule,
|
||||||
|
NgxPaginationModule,
|
||||||
|
DashboardRoutingModule,
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
DashboardComponent,
|
||||||
|
DashboardCustomerComponent,
|
||||||
|
AccountEditComponent,
|
||||||
|
AddDataComponent,
|
||||||
|
OrgResultComponent,
|
||||||
|
OrgTableComponent,
|
||||||
|
TransactionLogComponent,
|
||||||
|
TransactionResultComponent,
|
||||||
|
FeedbackComponent,
|
||||||
|
GraphWidget,
|
||||||
|
OrgBarSnippetComponent,
|
||||||
|
GraphPanel,
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
CurrencyPipe
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class DashboardModule { }
|
64
src/app/dashboard/dashboard.routing.ts
Normal file
64
src/app/dashboard/dashboard.routing.ts
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { Routes, RouterModule } from '@angular/router';
|
||||||
|
|
||||||
|
import { AuthGuard } from '../_guards/auth.guard';
|
||||||
|
import { OrgGuard } from '../_guards/org.guard';
|
||||||
|
import { CustomerGuard } from '../_guards/customer.guard';
|
||||||
|
|
||||||
|
import { DashboardComponent } from './dashboard.component';
|
||||||
|
import { DashboardCustomerComponent } from './dashboard-customer.component';
|
||||||
|
import { FullLayoutComponent } from '../layouts/full-layout.component';
|
||||||
|
import { AccountEditComponent } from './account-edit.component';
|
||||||
|
import { AddDataComponent } from './add-data.component';
|
||||||
|
import { FeedbackComponent } from './feedback.component';
|
||||||
|
import { TransactionLogComponent } from './transaction-log.component';
|
||||||
|
|
||||||
|
// Using child path to allow for FullLayout theming
|
||||||
|
const routes: Routes = [
|
||||||
|
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: FullLayoutComponent,
|
||||||
|
canActivate: [AuthGuard],
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'dashboard',
|
||||||
|
component: DashboardComponent,
|
||||||
|
data: { title: 'Dashboard' },
|
||||||
|
canActivate: [OrgGuard],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'dashboard-customer',
|
||||||
|
component: DashboardCustomerComponent,
|
||||||
|
data: { title: 'Customer Dashboard' },
|
||||||
|
canActivate: [CustomerGuard],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'account-edit',
|
||||||
|
component: AccountEditComponent,
|
||||||
|
data: { title: 'Leaderboards' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'add-data',
|
||||||
|
component: AddDataComponent,
|
||||||
|
data: { title: 'Add Transaction' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'transaction-log',
|
||||||
|
component: TransactionLogComponent,
|
||||||
|
data: { title: 'Transaction Log' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'feedback',
|
||||||
|
component: FeedbackComponent,
|
||||||
|
data: { title: 'Give Feedback' },
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forChild(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class DashboardRoutingModule {}
|
45
src/app/dashboard/feedback.component.html
Normal file
45
src/app/dashboard/feedback.component.html
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<div class="animated fadeIn">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<strong>Submit Transaction</strong>
|
||||||
|
<small>Required Data marked in <strong>bold</strong>.</small>
|
||||||
|
</div>
|
||||||
|
<form class="form-horizontal" [formGroup]="feedbackForm" (ngSubmit)="onSubmit()">
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Email</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<input type="text" class="form-control" name="email" formControlName="email" placeholder="Enter Account Email Here" [(ngModel)]="loggedInEmail" [disabled]="noEmail">
|
||||||
|
<span class="help-block">Enter your email here if it doesn't show.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Enter Feedback Here</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<textarea rows="7" class="form-control" formControlName="feedbacktext"></textarea>
|
||||||
|
<span class="help-block">Please enter your feedback in this textbox.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col-md-9">
|
||||||
|
<div [ngSwitch]="feedbackFormStatus">
|
||||||
|
<div *ngSwitchCase="'success'" class="alert alert-success" role="alert">
|
||||||
|
Thank you for submitting feedback!
|
||||||
|
</div>
|
||||||
|
<div *ngSwitchCase="'send_failed'" class="alert alert-danger" role="alert">
|
||||||
|
{{feedbackFormStatusError}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<button type="submit" [disabled]="!feedbackForm.valid" class="btn btn-sm btn-primary"><i class="fa fa-dot-circle-o"></i> Submit</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!--/.row-->
|
||||||
|
</div>
|
90
src/app/dashboard/feedback.component.ts
Normal file
90
src/app/dashboard/feedback.component.ts
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Validators, FormBuilder, FormGroup } from '@angular/forms';
|
||||||
|
import { Http, Response } from '@angular/http';
|
||||||
|
import { ApiService } from '../providers/api-service';
|
||||||
|
import 'rxjs/add/operator/map';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: 'feedback.component.html',
|
||||||
|
})
|
||||||
|
export class FeedbackComponent {
|
||||||
|
feedbackForm: FormGroup;
|
||||||
|
loggedInEmail: string;
|
||||||
|
noEmail: boolean = false;
|
||||||
|
username: any;
|
||||||
|
feedbackFormStatus: any;
|
||||||
|
feedbackFormStatusError: string = 'Error received, please try again.';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private http: Http,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private api: ApiService,
|
||||||
|
) {
|
||||||
|
this.feedbackForm = this.formBuilder.group({
|
||||||
|
email: ['', [Validators.required]],
|
||||||
|
feedbacktext: ['', [Validators.required]],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
|
||||||
|
if(localStorage.getItem('email')) {
|
||||||
|
this.loggedInEmail = localStorage.getItem('email');
|
||||||
|
}
|
||||||
|
console.log('loggedInEmail: ' + this.loggedInEmail);
|
||||||
|
if (this.loggedInEmail) {
|
||||||
|
console.log('email not found in storage');
|
||||||
|
this.api.accountFullLoad().subscribe(
|
||||||
|
result => {
|
||||||
|
console.log(result);
|
||||||
|
this.feedbackForm.patchValue({
|
||||||
|
email: result.email,
|
||||||
|
});
|
||||||
|
this.api.setUserInfo( result.email, result.display_name || result.name );
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log( error._body );
|
||||||
|
this.noEmail = true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit() {
|
||||||
|
this.api
|
||||||
|
.feedback(this.feedbackForm.value)
|
||||||
|
.subscribe(
|
||||||
|
result => {
|
||||||
|
if ( result.success == true ) {
|
||||||
|
console.log('Successful Upload');
|
||||||
|
console.log(result);
|
||||||
|
this.feedbackFormStatus = "success";
|
||||||
|
console.log(this.feedbackFormStatus);
|
||||||
|
this.feedbackForm.patchValue({
|
||||||
|
feedbacktext: '',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log('Upload Error');
|
||||||
|
this.feedbackFormStatusError = JSON.stringify(result.status) + 'Error, ' + JSON.stringify(result.message);
|
||||||
|
this.feedbackFormStatus = "send_failed";
|
||||||
|
console.log(this.feedbackFormStatus);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log('Upload Error');
|
||||||
|
console.log(error);
|
||||||
|
try {
|
||||||
|
console.log(error.error);
|
||||||
|
let jsonError = error.json();
|
||||||
|
console.log("boop");
|
||||||
|
this.feedbackFormStatusError = '"' + jsonError.error + '" Error, ' + jsonError.message;
|
||||||
|
} catch(e) {
|
||||||
|
this.feedbackFormStatusError = 'There was a server error, please try again later.';
|
||||||
|
}
|
||||||
|
this.feedbackFormStatus = "send_failed";
|
||||||
|
console.log(this.feedbackFormStatus);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
49
src/app/dashboard/transaction-log.component.html
Normal file
49
src/app/dashboard/transaction-log.component.html
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<div class="animated fadeIn">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<strong>Log of Outgoing Transactions</strong>
|
||||||
|
<small>This lists all purchases that have been submitted.</small>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="!noTransactionList" class="card-block">
|
||||||
|
<table class="table table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Seller</th>
|
||||||
|
<th>Value</th>
|
||||||
|
<th>Purchase Time</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr transaction-result *ngFor="let transaction of transactionList | paginate: paginateConfig" [transaction]="transaction"></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<pagination-template #p="paginationApi"
|
||||||
|
[id]="paginateConfig.id"
|
||||||
|
(pageChange)="loadTransactions($event)">
|
||||||
|
<ul class="pagination">
|
||||||
|
<li class="page-item" [class.disabled]="p.isFirstPage()">
|
||||||
|
<a class="page-link clickable" *ngIf="!p.isFirstPage()" (click)="p.previous()">Prev</a>
|
||||||
|
</li>
|
||||||
|
<li *ngFor="let page of p.pages" class="page-item" [class.active]="p.getCurrent() === page.value">
|
||||||
|
<a class="page-link clickable" (click)="p.setCurrent(page.value)" *ngIf="p.getCurrent() !== page.value">
|
||||||
|
<span>{{ page.label }}</span>
|
||||||
|
</a>
|
||||||
|
<div class="page-link" *ngIf="p.getCurrent() === page.value">
|
||||||
|
<span>{{ page.label }}</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="page-item" [class.disabled]="p.isLastPage()">
|
||||||
|
<a class="page-link clickable" *ngIf="!p.isLastPage()" (click)="p.next()">Next</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</pagination-template>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="noTransactionList" class="card-block">
|
||||||
|
No Transactions available.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
77
src/app/dashboard/transaction-log.component.ts
Normal file
77
src/app/dashboard/transaction-log.component.ts
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||||
|
import { Http, Response } from '@angular/http';
|
||||||
|
import { ApiService } from '../providers/api-service';
|
||||||
|
// import { PaginatePipe } from 'ngx-pagination';
|
||||||
|
import {PaginationInstance} from 'ngx-pagination';
|
||||||
|
// import { PaginationControlsComponent } from 'ngx-pagination';
|
||||||
|
// import { PaginationControlsDirective } from 'ngx-pagination';
|
||||||
|
// import { TransactionResultComponent } from '../shared/transaction-result.component';
|
||||||
|
import * as moment from 'moment';
|
||||||
|
import 'rxjs/add/operator/map';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: 'transaction-log.component.html',
|
||||||
|
})
|
||||||
|
export class TransactionLogComponent {
|
||||||
|
|
||||||
|
transactionList;
|
||||||
|
noTransactionList = true;
|
||||||
|
myDate: any;
|
||||||
|
minDate: any;
|
||||||
|
|
||||||
|
public paginateConfig: PaginationInstance = {
|
||||||
|
id: 'transpaginate',
|
||||||
|
itemsPerPage: 10,
|
||||||
|
currentPage: 1,
|
||||||
|
totalItems: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private http: Http,
|
||||||
|
private api: ApiService,
|
||||||
|
) {
|
||||||
|
this.myDate = moment().format('YYYY-MM-DD[T]HH:mm');
|
||||||
|
// this.myDate = new Date().toISOString().slice(0, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.getMinDate();
|
||||||
|
this.loadTransactions(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
getMinDate(){
|
||||||
|
// gets the April 1st date of the current year
|
||||||
|
let aprilDate = moment().month(3).date(1);
|
||||||
|
let now = moment();
|
||||||
|
// Checks if current time is before April 1st, if so returns true
|
||||||
|
let beforeApril = now.isBefore(aprilDate);
|
||||||
|
if ( beforeApril == true ) {
|
||||||
|
this.minDate = aprilDate.subtract(2, 'years').format('YYYY-MM-DD');
|
||||||
|
} else {
|
||||||
|
this.minDate = aprilDate.subtract(1, 'years').format('YYYY-MM-DD');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadTransactions(logPage: number) {
|
||||||
|
console.log(logPage);
|
||||||
|
this.api.transList(logPage).subscribe(
|
||||||
|
result => {
|
||||||
|
if(result.transactions.length > 0) {
|
||||||
|
this.transactionList = result.transactions;
|
||||||
|
//TODO Rename in server
|
||||||
|
this.paginateConfig.totalItems = result.page_no;
|
||||||
|
this.paginateConfig.currentPage = logPage;
|
||||||
|
this.noTransactionList = false;
|
||||||
|
} else {
|
||||||
|
// handle the case when the transactionList is empty
|
||||||
|
this.transactionList = null;
|
||||||
|
this.noTransactionList = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
71
src/app/layouts/full-layout.component.html
Normal file
71
src/app/layouts/full-layout.component.html
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
<header class="app-header navbar">
|
||||||
|
<button class="navbar-toggler d-lg-none" type="button" appMobileSidebarToggler>☰</button>
|
||||||
|
<a class="navbar-brand" href="#"></a>
|
||||||
|
<ul class="nav navbar navbar-nav">
|
||||||
|
<li class="nav-item dropdown" dropdown (onToggle)="toggled($event)">
|
||||||
|
<a href class="nav-link dropdown-toggle" dropdownToggle (click)="false">
|
||||||
|
<img src="assets/img/avatars/default.png" class="img-avatar" alt="avatar-image">
|
||||||
|
<span class="d-md-down-none">{{displayName}}</span>
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-menu dropdown-menu-right" *dropdownMenu aria-labelledby="simple-dropdown">
|
||||||
|
|
||||||
|
<div class="dropdown-header text-center"><strong>Settings</strong></div>
|
||||||
|
|
||||||
|
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/account-edit']">
|
||||||
|
<i class="fa fa-user"></i> Account Settings
|
||||||
|
</a>
|
||||||
|
<div class="divider"></div>
|
||||||
|
<a class="dropdown-item" (click)="userLogout()" href="#"><i class="fa fa-lock"></i> Logout</a>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="app-body">
|
||||||
|
<div class="sidebar">
|
||||||
|
<nav class="sidebar-nav">
|
||||||
|
<ul class="nav">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" routerLinkActive="active" [routerLink]="['/dashboard']">
|
||||||
|
<i class="icon-speedometer"></i> Dashboard
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" routerLinkActive="active" [routerLink]="['/add-data']">
|
||||||
|
<i class="icon-basket"></i> Add Transaction
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" routerLinkActive="active" [routerLink]="['/feedback']">
|
||||||
|
<i class="icon-envelope-letter"></i> Enter Feedback
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" routerLinkActive="active" [routerLink]="['/transaction-log']">
|
||||||
|
<i class="icon-basket"></i> Transaction Log
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Main content -->
|
||||||
|
<main class="main">
|
||||||
|
|
||||||
|
<!-- Breadcrumb -->
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<app-breadcrumbs></app-breadcrumbs>
|
||||||
|
<!-- Breadcrumb Menu-->
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<router-outlet></router-outlet>
|
||||||
|
</div><!-- /.conainer-fluid -->
|
||||||
|
</main>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="app-footer">
|
||||||
|
<a href="http://coreui.io">CoreUI</a> © 2017 creativeLabs.
|
||||||
|
<span class="float-right">Powered by <a href="http://coreui.io">CoreUI</a></span>
|
||||||
|
</footer>
|
47
src/app/layouts/full-layout.component.ts
Normal file
47
src/app/layouts/full-layout.component.ts
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ApiService } from '../providers/api-service';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-dashboard',
|
||||||
|
templateUrl: './full-layout.component.html',
|
||||||
|
})
|
||||||
|
export class FullLayoutComponent implements OnInit {
|
||||||
|
displayName: any;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private api: ApiService,
|
||||||
|
private router: Router,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public disabled = false;
|
||||||
|
public status: {isopen: boolean} = {isopen: false};
|
||||||
|
|
||||||
|
public toggled(open: boolean): void {
|
||||||
|
console.log('Dropdown is now: ', open);
|
||||||
|
}
|
||||||
|
|
||||||
|
public toggleDropdown($event: MouseEvent): void {
|
||||||
|
$event.preventDefault();
|
||||||
|
$event.stopPropagation();
|
||||||
|
this.status.isopen = !this.status.isopen;
|
||||||
|
}
|
||||||
|
|
||||||
|
// getDisplayName function from api didnt work
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.displayName = localStorage.getItem('displayname') || 'User';
|
||||||
|
}
|
||||||
|
|
||||||
|
userLogout() {
|
||||||
|
console.log('logout clicked');
|
||||||
|
this.api
|
||||||
|
.logout()
|
||||||
|
.subscribe(
|
||||||
|
result => {
|
||||||
|
console.log('Logged out!');
|
||||||
|
localStorage.clear();
|
||||||
|
this.router.navigate(['/login']);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
12
src/app/layouts/simple-layout.component.ts
Normal file
12
src/app/layouts/simple-layout.component.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-dashboard',
|
||||||
|
template: '<router-outlet></router-outlet>',
|
||||||
|
})
|
||||||
|
export class SimpleLayoutComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit(): void { }
|
||||||
|
}
|
16
src/app/pages/404.component.html
Normal file
16
src/app/pages/404.component.html
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<div class="app flex-row align-items-center">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="clearfix">
|
||||||
|
<h1 class="float-left display-3 mr-4">404</h1>
|
||||||
|
<h4 class="pt-3">Oops! You're lost.</h4>
|
||||||
|
<p class="text-muted">The page you are looking for was not found.</p>
|
||||||
|
</div>
|
||||||
|
<span class="input-group-btn">
|
||||||
|
<button class="btn btn-primary btn-lg" type="button"(click)="goBack()">Go Back</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
17
src/app/pages/404.component.ts
Normal file
17
src/app/pages/404.component.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { Location } from '@angular/common';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: '404.component.html'
|
||||||
|
})
|
||||||
|
export class P404Component {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private location: Location
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
goBack(): void {
|
||||||
|
this.location.back();
|
||||||
|
}
|
||||||
|
}
|
16
src/app/pages/500.component.html
Normal file
16
src/app/pages/500.component.html
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<div class="app flex-row align-items-center">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="clearfix">
|
||||||
|
<h1 class="float-left display-3 mr-4">500</h1>
|
||||||
|
<h4 class="pt-3">Houston, we have a problem!</h4>
|
||||||
|
<p class="text-muted">The page you are looking for is temporarily unavailable.</p>
|
||||||
|
</div>
|
||||||
|
<span class="input-group-btn">
|
||||||
|
<button class="btn btn-primary btn-lg" type="button"(click)="goBack()">Go Back</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
17
src/app/pages/500.component.ts
Normal file
17
src/app/pages/500.component.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { Location } from '@angular/common';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: '500.component.html'
|
||||||
|
})
|
||||||
|
export class P500Component {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private location: Location
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
goBack(): void {
|
||||||
|
this.location.back();
|
||||||
|
}
|
||||||
|
}
|
29
src/app/panels/graph-panel.component.html
Normal file
29
src/app/panels/graph-panel.component.html
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-5">
|
||||||
|
<h4 class="card-title mb-0">Customers</h4>
|
||||||
|
</div><!--/.col-->
|
||||||
|
<div class="col-sm-7 hidden-sm-down">
|
||||||
|
<div class="btn-toolbar float-right" role="toolbar" aria-label="Toolbar with button groups">
|
||||||
|
<div class="btn-group mr-3" data-toggle="buttons" aria-label="First group">
|
||||||
|
<label class="btn btn-outline-secondary active">
|
||||||
|
<input type="radio" name="options" id="option2" checked> Week
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!--/.col-->
|
||||||
|
</div><!--/.row-->
|
||||||
|
<div class="chart-wrapper" style="height:300px;margin-top:40px;">
|
||||||
|
<canvas baseChart class="chart"
|
||||||
|
[datasets]="chartData"
|
||||||
|
[labels]="chartLabels"
|
||||||
|
[options]="mainChartOptions"
|
||||||
|
[colors]="mainChartColours"
|
||||||
|
[legend]="chartLegend"
|
||||||
|
[chartType]="chartType"
|
||||||
|
(chartHover)="chartHovered($event)"
|
||||||
|
(chartClick)="chartClicked($event)"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
145
src/app/panels/graph-panel.component.ts
Normal file
145
src/app/panels/graph-panel.component.ts
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||||
|
import { OrgGraphsService } from '../providers/org-graphs.service';
|
||||||
|
import { DataType } from '../shared/data-types.enum';
|
||||||
|
import { ChartData } from '../_interfaces/chart-data';
|
||||||
|
import * as moment from 'moment';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'panel-graph',
|
||||||
|
templateUrl: 'graph-panel.component.html',
|
||||||
|
})
|
||||||
|
export class GraphPanel implements OnInit {
|
||||||
|
|
||||||
|
public chartType = 'line';
|
||||||
|
public chartLegend = true;
|
||||||
|
|
||||||
|
public rawChartData: Array<number> = [];
|
||||||
|
|
||||||
|
public chartData: Array<ChartData> = [
|
||||||
|
{
|
||||||
|
data: [],
|
||||||
|
label: 'This Week'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: [],
|
||||||
|
label: 'Last Week'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: [],
|
||||||
|
label: 'Week Before Last'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
public rawChartLabels: Array<string> = [];
|
||||||
|
public chartLabels: Array<string> = [];
|
||||||
|
|
||||||
|
public brandSuccess = '#4dbd74';
|
||||||
|
public brandInfo = '#63c2de';
|
||||||
|
public brandDanger = '#f86c6b';
|
||||||
|
|
||||||
|
public mainChartElements = 7;
|
||||||
|
|
||||||
|
public mainChartOptions: any = {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
scales: {
|
||||||
|
xAxes: [{
|
||||||
|
type: 'time',
|
||||||
|
time: {
|
||||||
|
unit: 'day',
|
||||||
|
displayFormats: {
|
||||||
|
day: 'dddd',
|
||||||
|
},
|
||||||
|
tooltipFormat: 'dddd',
|
||||||
|
},
|
||||||
|
gridLines: {
|
||||||
|
drawOnChartArea: false,
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
yAxes: [{
|
||||||
|
ticks: {
|
||||||
|
beginAtZero: true,
|
||||||
|
stepSize: 1,
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
elements: {
|
||||||
|
line: {
|
||||||
|
borderWidth: 2
|
||||||
|
},
|
||||||
|
point: {
|
||||||
|
radius: 0,
|
||||||
|
hitRadius: 10,
|
||||||
|
hoverRadius: 4,
|
||||||
|
hoverBorderWidth: 3,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
public mainChartColours: Array<any> = [
|
||||||
|
{ // brandInfo
|
||||||
|
backgroundColor: this.convertHex(this.brandInfo, 10),
|
||||||
|
borderColor: this.brandInfo,
|
||||||
|
pointHoverBackgroundColor: '#fff'
|
||||||
|
},
|
||||||
|
{ // brandSuccess
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
borderColor: this.brandSuccess,
|
||||||
|
pointHoverBackgroundColor: '#fff'
|
||||||
|
},
|
||||||
|
{ // brandDanger
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
borderColor: this.brandDanger,
|
||||||
|
pointHoverBackgroundColor: '#fff',
|
||||||
|
borderWidth: 1,
|
||||||
|
borderDash: [8, 5]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private graphService: OrgGraphsService,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
public ngOnInit(): void {
|
||||||
|
const end = moment().startOf('day');
|
||||||
|
const start = end.clone().subtract(this.mainChartElements * 3, 'days');
|
||||||
|
this.graphService.getGraph('customers_range', {
|
||||||
|
start: start.format('YYYY-MM-DD'),
|
||||||
|
end: end.format('YYYY-MM-DD'),
|
||||||
|
}).subscribe( result => this.setData(result.graph) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private setData(data: any) {
|
||||||
|
this.chartLabels = data.labels.slice(this.mainChartElements * 2, this.mainChartElements * 3);
|
||||||
|
this.chartData[2].data = data.data.slice(0, this.mainChartElements);
|
||||||
|
this.chartData[1].data = data.data.slice(this.mainChartElements, this.mainChartElements * 2);
|
||||||
|
this.chartData[0].data = data.data.slice(this.mainChartElements * 2, this.mainChartElements * 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert Hex to RGBA
|
||||||
|
public convertHex(hex: string, opacity: number) {
|
||||||
|
hex = hex.replace('#', '');
|
||||||
|
const r = parseInt(hex.substring(0, 2), 16);
|
||||||
|
const g = parseInt(hex.substring(2, 4), 16);
|
||||||
|
const b = parseInt(hex.substring(4, 6), 16);
|
||||||
|
|
||||||
|
const rgba = 'rgba(' + r + ', ' + g + ', ' + b + ', ' + opacity / 100 + ')';
|
||||||
|
return rgba;
|
||||||
|
}
|
||||||
|
|
||||||
|
// events
|
||||||
|
public chartClicked(e: any): void {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public chartHovered(e: any): void {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// mainChart
|
||||||
|
|
||||||
|
public random(min: number, max: number) {
|
||||||
|
return Math.floor(Math.random() * (max - min + 1) + min);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
264
src/app/providers/api-service.ts
Normal file
264
src/app/providers/api-service.ts
Normal file
|
@ -0,0 +1,264 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Http } from '@angular/http';
|
||||||
|
import { Observable } from 'rxjs/Rx';
|
||||||
|
import { environment } from '../../environments/environment';
|
||||||
|
import 'rxjs/add/operator/map';
|
||||||
|
|
||||||
|
/* this provider handles the interaction between server and client */
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ApiService {
|
||||||
|
private apiUrl = environment.apiUrl;
|
||||||
|
private sessionKey: string = null;
|
||||||
|
constructor(
|
||||||
|
private http: Http,
|
||||||
|
) {
|
||||||
|
if (localStorage.getItem('sessionKey') ) {
|
||||||
|
this.sessionKey = localStorage.getItem('sessionKey');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public post(url: string, data: any = {}) {
|
||||||
|
data.session_key = this.sessionKey;
|
||||||
|
return this.http.post(
|
||||||
|
this.apiUrl + url,
|
||||||
|
data
|
||||||
|
).map( response => response.json() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Login API
|
||||||
|
|
||||||
|
public getSessionKey() {
|
||||||
|
console.log('get key');
|
||||||
|
return this.sessionKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setSessionKey(key) {
|
||||||
|
console.log('set key');
|
||||||
|
this.sessionKey = key;
|
||||||
|
localStorage.setItem('sessionKey', this.sessionKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeSessionKey() {
|
||||||
|
console.log('remove key');
|
||||||
|
this.sessionKey = null;
|
||||||
|
localStorage.removeItem('sessionKey');
|
||||||
|
}
|
||||||
|
|
||||||
|
public register(data) {
|
||||||
|
return this.http.post(
|
||||||
|
this.apiUrl + '/register',
|
||||||
|
data
|
||||||
|
).map( response => response.json() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public login(data) {
|
||||||
|
return this.http
|
||||||
|
.post(
|
||||||
|
this.apiUrl + '/login',
|
||||||
|
data
|
||||||
|
)
|
||||||
|
.map(
|
||||||
|
result => {
|
||||||
|
const json = result.json();
|
||||||
|
this.setSessionKey(json.session_key);
|
||||||
|
this.setUserInfo(
|
||||||
|
json.email,
|
||||||
|
json.display_name || json.name
|
||||||
|
);
|
||||||
|
this.setUserType(json.user_type);
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public logout() {
|
||||||
|
console.log(this.sessionKey);
|
||||||
|
const key = this.sessionKey;
|
||||||
|
return this.http
|
||||||
|
.post(
|
||||||
|
this.apiUrl + '/logout',
|
||||||
|
{ session_key : key },
|
||||||
|
)
|
||||||
|
.map(
|
||||||
|
response => {
|
||||||
|
localStorage.clear();
|
||||||
|
this.sessionKey = null;
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Submits feedback
|
||||||
|
|
||||||
|
public feedback(data) {
|
||||||
|
data.app_name = 'Foodloop Web';
|
||||||
|
data.package_name = 'Foodloop Web';
|
||||||
|
data.version_code = 'dev';
|
||||||
|
data.version_number = 'dev';
|
||||||
|
console.log(data);
|
||||||
|
return this.http.post(
|
||||||
|
this.apiUrl + '/feedback',
|
||||||
|
data
|
||||||
|
).map( response => response.json() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// gets transaction list for log
|
||||||
|
|
||||||
|
public transList(data) {
|
||||||
|
const key = this.sessionKey;
|
||||||
|
return this.http.post(
|
||||||
|
this.apiUrl + '/outgoing-transactions',
|
||||||
|
{
|
||||||
|
session_key : key,
|
||||||
|
page : data
|
||||||
|
}
|
||||||
|
).map( response => response.json() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Searches organisations used for transaction submission
|
||||||
|
|
||||||
|
public search(data) {
|
||||||
|
data.session_key = this.sessionKey;
|
||||||
|
return this.http.post(
|
||||||
|
this.apiUrl + '/search',
|
||||||
|
data
|
||||||
|
).map( response => response.json() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uploads a transaction
|
||||||
|
|
||||||
|
public upload(data) {
|
||||||
|
data.session_key = this.sessionKey;
|
||||||
|
return this.http.post(
|
||||||
|
this.apiUrl + '/upload',
|
||||||
|
data
|
||||||
|
).map( response => response.json() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// handles Org data added
|
||||||
|
|
||||||
|
public orgPayroll(data) {
|
||||||
|
data.session_key = this.sessionKey;
|
||||||
|
return this.http.post(
|
||||||
|
this.apiUrl + '/org/payroll',
|
||||||
|
data
|
||||||
|
).map( response => response.json() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public orgSupplier(data) {
|
||||||
|
data.session_key = this.sessionKey;
|
||||||
|
return this.http.post(
|
||||||
|
this.apiUrl + '/org/supplier',
|
||||||
|
data
|
||||||
|
).map( response => response.json() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public orgEmployee(data) {
|
||||||
|
data.session_key = this.sessionKey;
|
||||||
|
return this.http.post(
|
||||||
|
this.apiUrl + '/org/employee',
|
||||||
|
data
|
||||||
|
).map( response => response.json() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handles user data interaction
|
||||||
|
|
||||||
|
// Checks for login status
|
||||||
|
|
||||||
|
public hasLoggedIn() {
|
||||||
|
return this.getSessionKey() ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pulls user info to store locally on login
|
||||||
|
|
||||||
|
public setUserInfo(
|
||||||
|
email: string,
|
||||||
|
display_name: string) {
|
||||||
|
console.log('set UserInfo');
|
||||||
|
localStorage.setItem('email', email);
|
||||||
|
localStorage.setItem('displayname', display_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets usertype
|
||||||
|
|
||||||
|
public setUserType(user_type: string) {
|
||||||
|
console.log('set UserType');
|
||||||
|
localStorage.setItem('usertype', user_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used for getting account details and updating
|
||||||
|
|
||||||
|
public accountFullLoad() {
|
||||||
|
const key = this.sessionKey;
|
||||||
|
return this.http.post(
|
||||||
|
this.apiUrl + '/user',
|
||||||
|
{ session_key : key },
|
||||||
|
).map( response => response.json() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public accountEditUpdate(data) {
|
||||||
|
data.session_key = this.sessionKey;
|
||||||
|
return this.http.post(
|
||||||
|
this.apiUrl + '/user/account',
|
||||||
|
data
|
||||||
|
).map( response => response.json() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deletes account details on logout
|
||||||
|
|
||||||
|
public removeUserInfo() {
|
||||||
|
console.log('remove UserInfo');
|
||||||
|
localStorage.removeItem('email');
|
||||||
|
localStorage.removeItem('displayname');
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFullName() {
|
||||||
|
console.log('get Full Name');
|
||||||
|
localStorage.getItem('fullname');
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDisplayName() {
|
||||||
|
console.log('get Display Name');
|
||||||
|
localStorage.getItem('displayname');
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPostcode() {
|
||||||
|
console.log('get Postcode');
|
||||||
|
localStorage.getItem('postcode');
|
||||||
|
}
|
||||||
|
|
||||||
|
public getYearOfBirth() {
|
||||||
|
console.log('get Year of Birth');
|
||||||
|
localStorage.getItem('yearofbirth');
|
||||||
|
}
|
||||||
|
|
||||||
|
public getEmail() {
|
||||||
|
console.log('get email');
|
||||||
|
localStorage.getItem('email');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Leaderboard Api
|
||||||
|
|
||||||
|
public leaderboard_fetch(data) {
|
||||||
|
const key = this.sessionKey;
|
||||||
|
return this.http.post(
|
||||||
|
this.apiUrl + '/stats/leaderboard',
|
||||||
|
{
|
||||||
|
session_key : key,
|
||||||
|
type : data
|
||||||
|
}
|
||||||
|
).map( response => response.json() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic Customer User stats API
|
||||||
|
public basicStats() {
|
||||||
|
const key = this.sessionKey;
|
||||||
|
return this.http.post(
|
||||||
|
this.apiUrl + '/stats',
|
||||||
|
{
|
||||||
|
session_key : key,
|
||||||
|
}
|
||||||
|
).map( response => response.json() );
|
||||||
|
}
|
||||||
|
}
|
14
src/app/providers/org-graphs.service.ts
Normal file
14
src/app/providers/org-graphs.service.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { ApiService } from './api-service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class OrgGraphsService {
|
||||||
|
private orgGraphUrl = '/v1/organisation/graphs';
|
||||||
|
|
||||||
|
constructor(private api: ApiService) { }
|
||||||
|
|
||||||
|
public getGraph(name: string, data: any = {}) {
|
||||||
|
data.graph = name;
|
||||||
|
return this.api.post(this.orgGraphUrl, data);
|
||||||
|
}
|
||||||
|
}
|
14
src/app/providers/org-snippets.service.ts
Normal file
14
src/app/providers/org-snippets.service.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { ApiService } from './api-service';
|
||||||
|
import { Observable } from 'rxjs/Rx';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class OrgSnippetsService {
|
||||||
|
private orgSnippetsUrl = '/v1/organisation/snippets';
|
||||||
|
|
||||||
|
constructor(private api: ApiService) { }
|
||||||
|
|
||||||
|
public getData(): Observable<any> {
|
||||||
|
return this.api.post(this.orgSnippetsUrl);
|
||||||
|
}
|
||||||
|
}
|
17
src/app/shared/aside.directive.ts
Normal file
17
src/app/shared/aside.directive.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import { Directive, HostListener } from '@angular/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows the aside to be toggled via click.
|
||||||
|
*/
|
||||||
|
@Directive({
|
||||||
|
selector: '[appAsideMenuToggler]',
|
||||||
|
})
|
||||||
|
export class AsideToggleDirective {
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
@HostListener('click', ['$event'])
|
||||||
|
toggleOpen($event: any) {
|
||||||
|
$event.preventDefault();
|
||||||
|
document.querySelector('body').classList.toggle('aside-menu-hidden');
|
||||||
|
}
|
||||||
|
}
|
42
src/app/shared/breadcrumb.component.ts
Normal file
42
src/app/shared/breadcrumb.component.ts
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
|
||||||
|
import 'rxjs/add/operator/filter';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-breadcrumbs',
|
||||||
|
template: `
|
||||||
|
<ng-template ngFor let-breadcrumb [ngForOf]="breadcrumbs" let-last = last>
|
||||||
|
<li class="breadcrumb-item"
|
||||||
|
*ngIf="breadcrumb.label.title&&breadcrumb.url.substring(breadcrumb.url.length-1) == '/'||breadcrumb.label.title&&last"
|
||||||
|
[ngClass]="{active: last}">
|
||||||
|
<a *ngIf="!last" [routerLink]="breadcrumb.url">{{breadcrumb.label.title}}</a>
|
||||||
|
<span *ngIf="last" [routerLink]="breadcrumb.url">{{breadcrumb.label.title}}</span>
|
||||||
|
</li>
|
||||||
|
</ng-template>`
|
||||||
|
})
|
||||||
|
export class BreadcrumbsComponent implements OnInit {
|
||||||
|
breadcrumbs: Array<Object>;
|
||||||
|
constructor(private router: Router, private route: ActivatedRoute) {}
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.router.events.filter(event => event instanceof NavigationEnd).subscribe(event => {
|
||||||
|
this.breadcrumbs = [];
|
||||||
|
let currentRoute = this.route.root,
|
||||||
|
url = '';
|
||||||
|
do {
|
||||||
|
const childrenRoutes = currentRoute.children;
|
||||||
|
currentRoute = null;
|
||||||
|
childrenRoutes.forEach(route => {
|
||||||
|
if (route.outlet === 'primary') {
|
||||||
|
const routeSnapshot = route.snapshot;
|
||||||
|
url += '/' + routeSnapshot.url.map(segment => segment.path).join('/');
|
||||||
|
this.breadcrumbs.push({
|
||||||
|
label: route.snapshot.data,
|
||||||
|
url: url
|
||||||
|
});
|
||||||
|
currentRoute = route;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} while (currentRoute);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
4
src/app/shared/data-types.enum.ts
Normal file
4
src/app/shared/data-types.enum.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export enum DataType {
|
||||||
|
number,
|
||||||
|
currency,
|
||||||
|
}
|
31
src/app/shared/nav-dropdown.directive.ts
Normal file
31
src/app/shared/nav-dropdown.directive.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import { Directive, HostListener, ElementRef } from '@angular/core';
|
||||||
|
|
||||||
|
@Directive({
|
||||||
|
selector: '[appNavDropdown]'
|
||||||
|
})
|
||||||
|
export class NavDropdownDirective {
|
||||||
|
|
||||||
|
constructor(private el: ElementRef) { }
|
||||||
|
|
||||||
|
toggle() {
|
||||||
|
this.el.nativeElement.classList.toggle('open');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows the dropdown to be toggled via click.
|
||||||
|
*/
|
||||||
|
@Directive({
|
||||||
|
selector: '[appNavDropdownToggle]'
|
||||||
|
})
|
||||||
|
export class NavDropdownToggleDirective {
|
||||||
|
constructor(private dropdown: NavDropdownDirective) {}
|
||||||
|
|
||||||
|
@HostListener('click', ['$event'])
|
||||||
|
toggleOpen($event: any) {
|
||||||
|
$event.preventDefault();
|
||||||
|
this.dropdown.toggle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const NAV_DROPDOWN_DIRECTIVES = [NavDropdownDirective, NavDropdownToggleDirective];
|
4
src/app/shared/org-result.component.html
Normal file
4
src/app/shared/org-result.component.html
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<td (click)="orgClick()">{{org.name}}</td>
|
||||||
|
<td (click)="orgClick()">{{org.street_name}}</td>
|
||||||
|
<td (click)="orgClick()">{{org.town}}</td>
|
||||||
|
<td (click)="orgClick()">{{org.postcode}}</td>
|
24
src/app/shared/org-result.component.ts
Normal file
24
src/app/shared/org-result.component.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
||||||
|
|
||||||
|
interface OrgData {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
street_name: string;
|
||||||
|
town: string;
|
||||||
|
postcode: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: '[org-result]',
|
||||||
|
templateUrl: 'org-result.component.html',
|
||||||
|
})
|
||||||
|
export class OrgResultComponent {
|
||||||
|
@Input() public org: OrgData;
|
||||||
|
@Output() public onClick = new EventEmitter();
|
||||||
|
|
||||||
|
public orgClick(): void {
|
||||||
|
this.onClick.emit(
|
||||||
|
this.org
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
19
src/app/shared/org-table.component.html
Normal file
19
src/app/shared/org-table.component.html
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Organisation Search Results</strong></label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<span class="help-block"><strong>Select an Organisation from the table below</strong></span>
|
||||||
|
<table class="table table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Organisation Name</th>
|
||||||
|
<th>Street Name</th>
|
||||||
|
<th>Town</th>
|
||||||
|
<th>Postcode</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr org-result *ngFor="let org of orgList" [org]="org" (onClick)="orgClick($event)"></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
23
src/app/shared/org-table.component.ts
Normal file
23
src/app/shared/org-table.component.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
||||||
|
import { OrgResultComponent } from '../shared/org-result.component';
|
||||||
|
|
||||||
|
interface OrgData {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
street_name: string;
|
||||||
|
town: string;
|
||||||
|
postcode: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'org-table',
|
||||||
|
templateUrl: 'org-table.component.html',
|
||||||
|
})
|
||||||
|
export class OrgTableComponent {
|
||||||
|
@Input() public orgList: Array<OrgData>;
|
||||||
|
@Output() public onClick = new EventEmitter();
|
||||||
|
|
||||||
|
public orgClick(event: any): void {
|
||||||
|
this.onClick.emit( event );
|
||||||
|
}
|
||||||
|
}
|
92
src/app/shared/sidebar.directive.ts
Normal file
92
src/app/shared/sidebar.directive.ts
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
import { Directive, HostListener } from '@angular/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows the sidebar to be toggled via click.
|
||||||
|
*/
|
||||||
|
@Directive({
|
||||||
|
selector: '[appSidebarToggler]'
|
||||||
|
})
|
||||||
|
export class SidebarToggleDirective {
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
@HostListener('click', ['$event'])
|
||||||
|
toggleOpen($event: any) {
|
||||||
|
$event.preventDefault();
|
||||||
|
document.querySelector('body').classList.toggle('sidebar-hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Directive({
|
||||||
|
selector: '[appSidebarMinimizer]'
|
||||||
|
})
|
||||||
|
export class SidebarMinimizeDirective {
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
@HostListener('click', ['$event'])
|
||||||
|
toggleOpen($event: any) {
|
||||||
|
$event.preventDefault();
|
||||||
|
document.querySelector('body').classList.toggle('sidebar-minimized');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Directive({
|
||||||
|
selector: '[appMobileSidebarToggler]'
|
||||||
|
})
|
||||||
|
export class MobileSidebarToggleDirective {
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
// Check if element has class
|
||||||
|
private hasClass(target: any, elementClassName: string) {
|
||||||
|
return new RegExp('(\\s|^)' + elementClassName + '(\\s|$)').test(target.className);
|
||||||
|
}
|
||||||
|
|
||||||
|
@HostListener('click', ['$event'])
|
||||||
|
toggleOpen($event: any) {
|
||||||
|
$event.preventDefault();
|
||||||
|
document.querySelector('body').classList.toggle('sidebar-mobile-show');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows the off-canvas sidebar to be closed via click.
|
||||||
|
*/
|
||||||
|
@Directive({
|
||||||
|
selector: '[appSidebarClose]'
|
||||||
|
})
|
||||||
|
export class SidebarOffCanvasCloseDirective {
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
// Check if element has class
|
||||||
|
private hasClass(target: any, elementClassName: string) {
|
||||||
|
return new RegExp('(\\s|^)' + elementClassName + '(\\s|$)').test(target.className);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle element class
|
||||||
|
private toggleClass(elem: any, elementClassName: string) {
|
||||||
|
let newClass = ' ' + elem.className.replace( /[\t\r\n]/g, ' ' ) + ' ';
|
||||||
|
if (this.hasClass(elem, elementClassName)) {
|
||||||
|
while (newClass.indexOf(' ' + elementClassName + ' ') >= 0 ) {
|
||||||
|
newClass = newClass.replace( ' ' + elementClassName + ' ' , ' ' );
|
||||||
|
}
|
||||||
|
elem.className = newClass.replace(/^\s+|\s+$/g, '');
|
||||||
|
} else {
|
||||||
|
elem.className += ' ' + elementClassName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@HostListener('click', ['$event'])
|
||||||
|
toggleOpen($event: any) {
|
||||||
|
$event.preventDefault();
|
||||||
|
|
||||||
|
if (this.hasClass(document.querySelector('body'), 'sidebar-off-canvas')) {
|
||||||
|
this.toggleClass(document.querySelector('body'), 'sidebar-opened');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SIDEBAR_TOGGLE_DIRECTIVES = [
|
||||||
|
SidebarToggleDirective,
|
||||||
|
SidebarMinimizeDirective,
|
||||||
|
SidebarOffCanvasCloseDirective,
|
||||||
|
MobileSidebarToggleDirective
|
||||||
|
];
|
3
src/app/shared/transaction-result.component.html
Normal file
3
src/app/shared/transaction-result.component.html
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<td>{{transaction.seller}}</td>
|
||||||
|
<td>{{transaction.value | currency:'GBP':true:'1.2-2' }}</td>
|
||||||
|
<td>{{transactionDate}}</td>
|
21
src/app/shared/transaction-result.component.ts
Normal file
21
src/app/shared/transaction-result.component.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||||
|
import * as moment from 'moment';
|
||||||
|
|
||||||
|
interface TransactionData {
|
||||||
|
seller: number;
|
||||||
|
value: string;
|
||||||
|
purchase_time: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: '[transaction-result]',
|
||||||
|
templateUrl: 'transaction-result.component.html',
|
||||||
|
})
|
||||||
|
export class TransactionResultComponent implements OnInit {
|
||||||
|
@Input() public transaction: TransactionData;
|
||||||
|
public transactionDate: string;
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.transactionDate = moment(this.transaction.purchase_time).format('llll');
|
||||||
|
}
|
||||||
|
}
|
22
src/app/snippets/org-snippet-bar.component.html
Normal file
22
src/app/snippets/org-snippet-bar.component.html
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-footer">
|
||||||
|
<ul>
|
||||||
|
<li class="hidden-sm-down">
|
||||||
|
<div class="text-muted">Customers This Month</div>
|
||||||
|
<strong>{{ thisMonthSalesCount }}</strong>
|
||||||
|
</li>
|
||||||
|
<li class="hidden-sm-down">
|
||||||
|
<div class="text-muted">Money Spent This Month</div>
|
||||||
|
<strong>{{ thisMonthPurchasesTotal | currency:'GBP':true:'1.2-2'}}</strong>
|
||||||
|
</li>
|
||||||
|
<li class="hidden-sm-down">
|
||||||
|
<div class="text-muted">Customers Today</div>
|
||||||
|
<strong>{{ todaySalesCount }}</strong>
|
||||||
|
</li>
|
||||||
|
<li class="hidden-sm-down">
|
||||||
|
<div class="text-muted">Average Transaction Today</div>
|
||||||
|
<strong>{{ ( todaySalesTotal / todaySalesCount ) || 0 | currency:'GBP':true:'1.2-2'}}</strong>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue