Merge tag 'v0.0.1-alpha.1'

This commit is contained in:
Tom Bloor 2017-09-15 15:51:25 +01:00
commit 091179f627
503 changed files with 28671 additions and 1651 deletions

58
.angular-cli.json Normal file
View 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
View 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
View file

@ -17,6 +17,33 @@ $RECYCLE.BIN/
# Windows shortcuts
*.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
# =========================

21
LICENSE Normal file
View 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.

View file

@ -1,2 +1,63 @@
# FoodLoop-Web
For information on how to edit the CoreUI, see here: http://coreui.io/docs/getting-started/introduction
# LocalLoop Web Interface
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
View file

@ -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);
})

View file

@ -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
View 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
View 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
View file

@ -0,0 +1,13 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"jasminewd2",
"node"
]
}
}

View file

@ -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
View 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

File diff suppressed because it is too large Load diff

63
package.json Normal file
View 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"
}
}

View file

@ -1,3 +0,0 @@
<div ui-view="header"></div>
<div ui-view="sidebar"></div>
<div ui-view="main"></div>

View file

@ -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);
}
});

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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;
}

View file

@ -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>

View file

@ -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";
});

View file

@ -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-->

View file

@ -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");
}
});

View file

@ -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]}}
]}

View file

@ -1,3 +0,0 @@
#mapid { height: 180px; }
#map { width:600px; height: 600px }

View file

@ -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>

View file

@ -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: '&copy; ' + 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 +")";
}
)
}
})
})

View file

@ -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>

View file

@ -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
});

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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;
});

View file

@ -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

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -1,3 +0,0 @@
<user-header> </user-header>
<user-sidebar> </user-sidebar>
<user-main> </user-main>

View file

@ -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
View 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 } }));
}
};

View file

@ -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;
}
});

View file

@ -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
}
}]
}
}
});
}
});

View file

@ -1,6 +0,0 @@
/* this service handles receipt upload process */
app.service('uploadReceiptService', function () {
this.uploadReceipt = function(){
console.log("Upload successful");
}
});

View 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;
}
}

View 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;
}
}

View 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;
}
}

View file

@ -0,0 +1,4 @@
export interface ChartData {
data: Array<number>;
label: string;
}

View 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
View 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
View 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
View 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 {}

View 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 {}

View 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 {}

View 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>

View 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);
}
);
}
}

View 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>

View 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);
}
);
}
}

View 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>

View 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);
}
);
}
}

View 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>

View 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);
}
);
}
}

View 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>

View 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 {
}
}

View 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>

View 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() { }
}

View 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 { }

View 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 {}

View 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>

View 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);
}
);
}
}

View 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>

View 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);
}
);
}
}

View file

@ -0,0 +1,71 @@
<header class="app-header navbar">
<button class="navbar-toggler d-lg-none" type="button" appMobileSidebarToggler>&#9776;</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> &copy; 2017 creativeLabs.
<span class="float-right">Powered by <a href="http://coreui.io">CoreUI</a></span>
</footer>

View 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']);
}
);
}
}

View 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 { }
}

View 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>

View 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();
}
}

View 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>

View 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();
}
}

View 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>

View 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);
}
}

View 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() );
}
}

View 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);
}
}

View 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);
}
}

View 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');
}
}

View 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);
});
}
}

View file

@ -0,0 +1,4 @@
export enum DataType {
number,
currency,
}

View 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];

View 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>

View 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
)
}
}

View 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>

View 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 );
}
}

View 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
];

View file

@ -0,0 +1,3 @@
<td>{{transaction.seller}}</td>
<td>{{transaction.value | currency:'GBP':true:'1.2-2' }}</td>
<td>{{transactionDate}}</td>

View 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');
}
}

View 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