Merge branch 'Release-v0.1.13'
This commit is contained in:
commit
b91de60175
101 changed files with 12772 additions and 6505 deletions
|
@ -1,59 +0,0 @@
|
|||
{
|
||||
"$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.dev.ts",
|
||||
"prod": "environments/environment.prod.ts",
|
||||
"local": "environments/environment.local.ts",
|
||||
"ci": "environments/environment.ci.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
|
||||
}
|
||||
}
|
6
.gitattributes
vendored
6
.gitattributes
vendored
|
@ -15,3 +15,9 @@
|
|||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
||||
|
||||
# ensures font files are loaded as binary not text
|
||||
*.ttf binary
|
||||
*.eot binary
|
||||
*.woff binary
|
||||
*.woff2 binary
|
||||
|
|
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -22,7 +22,6 @@ $RECYCLE.BIN/
|
|||
/bower_components
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
*.launch
|
||||
|
@ -41,11 +40,15 @@ testem.log
|
|||
/e2e/*.js
|
||||
/e2e/*.map
|
||||
|
||||
# build
|
||||
/dist
|
||||
|
||||
# local env variable
|
||||
/src/environments/environment.local.ts
|
||||
/src/environments/environment.prod.ts
|
||||
/src/environments/environment.dev.ts
|
||||
/src/environments/environment.ci.ts
|
||||
/src/environments/environments.tar
|
||||
|
||||
# =========================
|
||||
# Operating System Files
|
||||
|
|
3
.idea/.gitignore
vendored
Normal file
3
.idea/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
|
||||
# Default ignored files
|
||||
/workspace.xml
|
6
.idea/misc.xml
Normal file
6
.idea/misc.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/Foodloop-Web.iml" filepath="$PROJECT_DIR$/Foodloop-Web.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
22
.travis.yml
22
.travis.yml
|
@ -2,14 +2,24 @@ addons:
|
|||
chrome: stable
|
||||
language: node_js
|
||||
node_js:
|
||||
- 8
|
||||
- node
|
||||
before_install:
|
||||
- openssl aes-256-cbc -K $encrypted_9d2af3734b6c_key -iv $encrypted_9d2af3734b6c_iv -in src/environments/environment.ci.ts.enc -out src/environments/environment.ci.ts -d
|
||||
- openssl aes-256-cbc -K $encrypted_17157b34afc7_key -iv $encrypted_17157b34afc7_iv -in src/environments/environments.tar.enc -out src/environments/environments.tar -d
|
||||
- tar xf src/environments/environments.tar -C src/environments
|
||||
before_script:
|
||||
- export DISPLAY=:99.0
|
||||
- sh -e /etc/init.d/xvfb start
|
||||
- npm config set spin false
|
||||
install:
|
||||
- npm install
|
||||
- npm install
|
||||
script:
|
||||
- npm run ci
|
||||
- npm run ci
|
||||
before_deploy:
|
||||
- ./bin/build-releases
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: "Ke27Qm16uRgfX+ZVAq92Suu0ZpLOG9TGXDD8ndKNQZ4zl80DOmePoKvVpk/5Ip3H57Me2seqtCwgjeUCfW0dX3KayPoNmGVxWXCsZCH3MZWuaMnGk/Zc1Ef8P3L1sTEG4LD6+59RaOiMwIrMtLPjSlzvV2gc+002O7MHoudx/qZl47L+T01B0Ovh1AueSVN224Q79NrBnbgTtMqaS3x2avLkJmdZpneafqeO5OusOFcvsHvBr7ca0qKv5yIpn4eotK2bo6TFuaC9e9i7gUgPKHb1/GXAK1DcteUDF3AzK/b7T+dqTS+1vowuNKjMZ+ecyB8VDXQlWnBcv/IGn/C3nBmtp2oN97BFQtHguCY42Qk9LZxIu9o0mpOt6aMRiIsfbWstgONKaLzgt4Ce3DFlJ7YR5BFRaoKDdGHoCW+tcucQ/o9vFCbBVZ8sol2aYJOiNHYxlC8A7NLs6YEjyckVAa3q1l6CddnSjrFA5oe9fsLdzUDGhJ57Nv7kF9v6jjsTlZtucrzf8ix9+vNKNfWLQ6K86UIeBT40pPYHLBmWEsiGai+s4IWrYjTscT4zQDHcfQCMuQbbb3NTEfy9Fwv0VQdIR/cKsQgUCZwwlv3RBImryuDFqY2pNOqvnGIcr/OJ/MmY9bbCYEp55dxrZ50dNBbtR4O8IyUDte/ycU4OKbE="
|
||||
file_glob: true
|
||||
file: "../WebApp-Releases/*"
|
||||
skip_cleanup: true
|
||||
on:
|
||||
tags: true
|
||||
|
|
103
CHANGELOG.md
103
CHANGELOG.md
|
@ -2,6 +2,109 @@
|
|||
|
||||
# Next Release
|
||||
|
||||
# 0.1.13
|
||||
|
||||
* Added new graphs for organisation view, for better breakdown of spending
|
||||
* Added Suppliers spend search page
|
||||
* Updated and fixes numerous graphs on dashboard
|
||||
|
||||
## Minor
|
||||
|
||||
* *Dev Fixes* Updated Travis config
|
||||
|
||||
|
||||
# 0.1.12
|
||||
|
||||
* Fixed accidentally added app-root
|
||||
|
||||
# 0.1.11
|
||||
|
||||
* Bumped Angular to version 6 and upgraded packages to match
|
||||
* Converted RxJS 5 syntax to RxJS 6
|
||||
* Removed extraneous console logs
|
||||
* Changed dashboard sector list to category all time list & tweaked layout
|
||||
|
||||
# 0.1.10
|
||||
|
||||
* Allowed for creation of yearly recurring transactions
|
||||
* Added google analytics
|
||||
|
||||
# 0.1.9
|
||||
|
||||
* Made layout change to make it neater when chart doesn't show
|
||||
* Made hotfix
|
||||
|
||||
# 0.1.8
|
||||
|
||||
* Amended how category is pulled from server
|
||||
* Added chart on essential purchase numbers as a whole
|
||||
* Added bar chart of category purchases in the month
|
||||
* Added pie chart of purchases by category in the week
|
||||
* Added hint for closing the burger menu while in mobile view
|
||||
|
||||
# v0.1.7
|
||||
|
||||
* Fixed category on upload highlighting
|
||||
|
||||
# v0.1.6
|
||||
|
||||
* Changed layout of category choosing on upload
|
||||
* Added ability to edit and remove recurring transactions
|
||||
* Fixed HttpClient error log viewing
|
||||
* Made transaction validation more lenient
|
||||
|
||||
# v0.1.5
|
||||
|
||||
* Fixed category viewing on purchase
|
||||
* Changed category view from radio buttons to full label buttons
|
||||
* Amended local validation of submit
|
||||
* Changed recurring purchase selection view
|
||||
|
||||
# v0.1.4
|
||||
|
||||
* Amended category list on transaction submission
|
||||
* Added budget view for weekly breakdown of spend by category
|
||||
* Added flag to make purchases essential
|
||||
* Fixed budget view issues and amended it to show essential purchases that week
|
||||
* Added ability to make purchases recurring
|
||||
* Updated Moment dependency due to security issue
|
||||
* Fixed category uploading in upload
|
||||
|
||||
# v0.1.3
|
||||
|
||||
* Made fix to Travis config
|
||||
|
||||
# v0.1.2
|
||||
|
||||
* Removed unused button
|
||||
* Added ability to choose category for transaction
|
||||
* Added version bump on Angular
|
||||
|
||||
# v0.1.1
|
||||
|
||||
* Redid layout on circle customer view
|
||||
* Renamed customer dashboard headers
|
||||
|
||||
# v0.1.0
|
||||
|
||||
* Changed Story Trail choosing to modals
|
||||
* Revamped snippets and graph widgets on customer dashboard
|
||||
* Added local purchase pie chart for customer dashboard
|
||||
* Added week by week purchase list for customer dashboard
|
||||
* Added sector purchase amount list for customer dashboard
|
||||
* Added sector U to available ones
|
||||
* Fixed snippet layout
|
||||
|
||||
# v0.0.7
|
||||
|
||||
* Added ESTA to Story Trail
|
||||
* Reverted Story Trail naming to LIS
|
||||
* Changed Trail map code to make it flexible based on association
|
||||
|
||||
# v0.0.6
|
||||
|
||||
* Fix typo in Map Titles
|
||||
|
||||
# v0.0.5
|
||||
|
||||
* Change page name from Story Trail to Lancaster Independent Story
|
||||
|
|
12
Foodloop-Web.iml
Normal file
12
Foodloop-Web.iml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/dist" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
177
angular.json
Normal file
177
angular.json
Normal file
|
@ -0,0 +1,177 @@
|
|||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"localloop-web": {
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"projectType": "application",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"tsConfig": "src/tsconfig.app.json",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"assets": [
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"src/scss/style.scss"
|
||||
],
|
||||
"scripts": [
|
||||
"node_modules/moment/min/moment.min.js"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"dev": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.dev.ts"
|
||||
}
|
||||
]
|
||||
},
|
||||
"production": {
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"extractCss": true,
|
||||
"namedChunks": false,
|
||||
"aot": true,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
]
|
||||
},
|
||||
"local": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.local.ts"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ci": {
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"extractCss": true,
|
||||
"namedChunks": false,
|
||||
"aot": true,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.ci.ts"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "localloop-web:build"
|
||||
},
|
||||
"configurations": {
|
||||
"dev": {
|
||||
"browserTarget": "localloop-web:build:dev"
|
||||
},
|
||||
"production": {
|
||||
"browserTarget": "localloop-web:build:production"
|
||||
},
|
||||
"local": {
|
||||
"browserTarget": "localloop-web:build:local"
|
||||
},
|
||||
"ci": {
|
||||
"browserTarget": "localloop-web:build:ci"
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "localloop-web:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "src/test.ts",
|
||||
"karmaConfig": "./karma.conf.js",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "src/tsconfig.spec.json",
|
||||
"styles": [
|
||||
"src/scss/style.scss"
|
||||
],
|
||||
"assets": [
|
||||
"src/assets"
|
||||
]
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"src/tsconfig.app.json",
|
||||
"src/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": []
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"localloop-web-e2e": {
|
||||
"root": "",
|
||||
"sourceRoot": "",
|
||||
"projectType": "application",
|
||||
"architect": {
|
||||
"e2e": {
|
||||
"builder": "@angular-devkit/build-angular:protractor",
|
||||
"options": {
|
||||
"protractorConfig": "./protractor.conf.js",
|
||||
"devServerTarget": "localloop-web:serve"
|
||||
},
|
||||
"configurations": {
|
||||
"local": {
|
||||
"devServerTarget": "localloop-web:serve:local"
|
||||
},
|
||||
"ci": {
|
||||
"devServerTarget": "localloop-web:serve:ci"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"e2e/tsconfig.e2e.json"
|
||||
],
|
||||
"exclude": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultProject": "localloop-web",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"prefix": "app",
|
||||
"styleext": "scss"
|
||||
},
|
||||
"@schematics/angular:directive": {
|
||||
"prefix": "app"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
#! /bin/bash
|
||||
set -e
|
||||
|
||||
VERSION=`git describe --tags`
|
||||
|
||||
|
@ -11,13 +12,13 @@ echo "Building releases for $VERSION"
|
|||
|
||||
echo "Building Prod Release..."
|
||||
|
||||
ng build --prod
|
||||
npm run build:prod
|
||||
|
||||
tar -czf ../WebApp-Releases/LocalLoop-Web-prod-$VERSION.tar.gz dist
|
||||
|
||||
echo "Building Dev Release..."
|
||||
|
||||
ng build --dev
|
||||
npm run build:dev
|
||||
|
||||
tar -czf ../WebApp-Releases/LocalLoop-Web-dev-$VERSION.tar.gz dist
|
||||
|
||||
|
|
12
browserslist
Normal file
12
browserslist
Normal file
|
@ -0,0 +1,12 @@
|
|||
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
|
||||
# You can see what browsers were selected by your queries by running:
|
||||
# npx browserslist
|
||||
|
||||
> 0.5%
|
||||
last 2 versions
|
||||
Firefox ESR
|
||||
not dead
|
||||
not IE 9-11 # For IE 9-11 support, remove 'not'.
|
|
@ -4,28 +4,28 @@
|
|||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular/cli'],
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular/cli/plugins/karma')
|
||||
require('@angular-devkit/build-angular/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' ],
|
||||
dir: require('path').join(__dirname, 'coverage'), reports: [ 'html', 'lcovonly' ],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
angularCli: {
|
||||
|
|
15253
package-lock.json
generated
15253
package-lock.json
generated
File diff suppressed because it is too large
Load diff
103
package.json
103
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "localloop-web",
|
||||
"version": "0.0.5",
|
||||
"version": "0.1.13",
|
||||
"description": "LocalLoop Web - Web interface for LocalLoop app",
|
||||
"author": "",
|
||||
"url": "http://www.peartrade.org",
|
||||
|
@ -8,59 +8,80 @@
|
|||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"start:dev": "ng serve --optimization=false --configuration=dev",
|
||||
"start:prod": "ng serve --optimization=false --configuration=production",
|
||||
"start:local": "ng serve --optimization=false --configuration=local",
|
||||
"build:dev": "ng build --configuration=dev",
|
||||
"build:prod": "ng build --configuration=production",
|
||||
"test": "ng test",
|
||||
"test:ci": "ng test --watch=false --env=ci",
|
||||
"test:ci": "ng test --watch=false --browsers=ChromeHeadless",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e",
|
||||
"e2e:ci": "ng e2e --env=ci",
|
||||
"e2e:ci": "ng e2e --configuration=ci",
|
||||
"ci": "npm run test:ci && npm run e2e:ci"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@agm/core": "1.0.0-beta.2",
|
||||
"@agm/js-marker-clusterer": "1.0.0-beta.2",
|
||||
"@angular/common": "5.0.1",
|
||||
"@angular/compiler": "5.0.1",
|
||||
"@angular/core": "5.0.1",
|
||||
"@angular/forms": "5.0.1",
|
||||
"@angular/platform-browser": "5.0.1",
|
||||
"@angular/platform-browser-dynamic": "5.0.1",
|
||||
"@angular/router": "5.0.1",
|
||||
"@angular/upgrade": "5.0.1",
|
||||
"@types/moment": "2.13.0",
|
||||
"chart.js": "2.7.1",
|
||||
"core-js": "2.5.1",
|
||||
"@agm/core": "1.0.0-beta.6",
|
||||
"@agm/js-marker-clusterer": "1.0.0-beta.6",
|
||||
"@angular/common": "8.1.0",
|
||||
"@angular/compiler": "8.1.0",
|
||||
"@angular/core": "8.1.0",
|
||||
"@angular/forms": "8.1.0",
|
||||
"@angular/platform-browser": "8.1.0",
|
||||
"@angular/platform-browser-dynamic": "8.1.0",
|
||||
"@angular/router": "8.1.0",
|
||||
"@angular/upgrade": "8.1.0",
|
||||
"@coreui/coreui-plugin-chartjs-custom-tooltips": "^1.3.1",
|
||||
"@coreui/icons": "0.3.0",
|
||||
"ajv": "^6.10.0",
|
||||
"ajv-keywords": "^3.4.0",
|
||||
"angular2-datetimepicker": "^1.1.1",
|
||||
"chart.js": "^2.8.0",
|
||||
"chartjs-adapter-luxon": "^0.2.0",
|
||||
"core-js": "^2.6.9",
|
||||
"devextreme": "^19.1.4",
|
||||
"devextreme-angular": "^19.1.4",
|
||||
"jasmine": "^3.4.0",
|
||||
"jquery": "^3.3.1",
|
||||
"js-marker-clusterer": "1.0.0",
|
||||
"moment": "^2.19.2",
|
||||
"ng2-charts": "1.6.0",
|
||||
"jszip": "^3.2.2",
|
||||
"luxon": "^1.16.1",
|
||||
"moment": "^2.24.0",
|
||||
"ng2-charts": "^2.3.0",
|
||||
"ng2-validation-manager": "0.5.3",
|
||||
"ngx-bootstrap": "2.0.0-beta.8",
|
||||
"ngx-pagination": "3.0.3",
|
||||
"rxjs": "5.5.2",
|
||||
"ngx-bootstrap": "^5.0.0",
|
||||
"ngx-filter-pipe": "^2.1.2",
|
||||
"ngx-pagination": "^4.0.0",
|
||||
"popper.js": "^1.15.0",
|
||||
"rxjs": "6.5.2",
|
||||
"stream": "0.0.2",
|
||||
"ts-helpers": "1.1.2",
|
||||
"webpack": "3.8.1",
|
||||
"webpack-dev-server": "2.9.4",
|
||||
"zone.js": "0.8.18"
|
||||
"tslib": "^1.10.0",
|
||||
"web-animations-js": "^2.3.2",
|
||||
"webpack-dev-server": "^3.7.2",
|
||||
"zone.js": "~0.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "1.5.0",
|
||||
"@angular/compiler-cli": "5.0.1",
|
||||
"@types/jasmine": "2.8.2",
|
||||
"@types/jasminewd2": "2.0.3",
|
||||
"@types/node": "8.0.52",
|
||||
"codelyzer": "4.0.1",
|
||||
"jasmine-core": "2.8.0",
|
||||
"@angular-devkit/build-angular": "~0.801.0",
|
||||
"@angular/cli": "^8.1.0",
|
||||
"@angular/compiler-cli": "8.1.0",
|
||||
"@types/jasmine": "3.3.13",
|
||||
"@types/jasminewd2": "2.0.6",
|
||||
"@types/node": "12.0.10",
|
||||
"codelyzer": "^5.1.0",
|
||||
"jasmine-core": "^3.4.0",
|
||||
"jasmine-spec-reporter": "4.2.1",
|
||||
"karma": "1.7.1",
|
||||
"karma": "^4.1.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.2.0",
|
||||
"ts-node": "3.3.0",
|
||||
"tslint": "5.8.0",
|
||||
"typescript": "2.4.2"
|
||||
"karma-cli": "2.0.0",
|
||||
"karma-coverage-istanbul-reporter": "^2.0.5",
|
||||
"karma-jasmine": "^2.0.1",
|
||||
"readable-stream": "latest",
|
||||
"karma-jasmine-html-reporter": "^1.4.2",
|
||||
"protractor": "^5.4.2",
|
||||
"ts-node": "^8.3.0",
|
||||
"tslint": "^5.18.0",
|
||||
"typescript": "~3.4.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,10 @@ exports.config = {
|
|||
'./e2e/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
'browserName': 'chrome'
|
||||
'browserName': 'chrome',
|
||||
chromeOptions: {
|
||||
args: [ "--headless" ]
|
||||
}
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
|
|
|
@ -8,13 +8,11 @@ export class AuthGuard implements CanActivate {
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -8,11 +8,9 @@ export class CustomerGuard implements CanActivate {
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -8,11 +8,9 @@ export class OrgGuard implements CanActivate {
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import { environment } from '../environments/environment';
|
||||
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { LocationStrategy, HashLocationStrategy } from '@angular/common';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
|
||||
|
@ -21,7 +24,11 @@ import { CustomerGuard } from './_guards/customer.guard';
|
|||
import { ApiService } from './providers/api-service';
|
||||
|
||||
import { OrgGraphsService } from './providers/org-graphs.service';
|
||||
import { CustGraphsService } from './providers/cust-graphs.service';
|
||||
import { OrgSnippetsService } from './providers/org-snippets.service';
|
||||
import { CustSnippetsService } from './providers/cust-snippets.service';
|
||||
import { CustPiesService } from './providers/cust-pies.service';
|
||||
import { OrgPiesService } from './providers/org-pies.service';
|
||||
|
||||
// Layouts
|
||||
import { FullLayoutComponent } from './layouts/full-layout.component';
|
||||
|
@ -34,21 +41,30 @@ import { P500Component } from './pages/500.component';
|
|||
// Submodules
|
||||
import { AuthModule } from './auth/auth.module';
|
||||
import { DashboardModule } from './dashboard/dashboard.module';
|
||||
import { ChartsModule } from 'ng2-charts';
|
||||
// import { StackedBarChartComponent } from './panels/stacked-bar.component';
|
||||
import { FilterPipeModule } from 'ngx-filter-pipe';
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
BrowserModule,
|
||||
HttpClientModule,
|
||||
FormsModule,
|
||||
FilterPipeModule,
|
||||
ReactiveFormsModule,
|
||||
NgxPaginationModule,
|
||||
BsDropdownModule.forRoot(),
|
||||
TabsModule.forRoot(),
|
||||
AuthModule,
|
||||
ChartsModule,
|
||||
DashboardModule,
|
||||
// Loaded last to allow for 404 catchall
|
||||
AppRoutingModule,
|
||||
],
|
||||
declarations: [
|
||||
AppComponent,
|
||||
// StackedBarChartComponent,
|
||||
FullLayoutComponent,
|
||||
SimpleLayoutComponent,
|
||||
NAV_DROPDOWN_DIRECTIVES,
|
||||
|
@ -65,6 +81,10 @@ import { DashboardModule } from './dashboard/dashboard.module';
|
|||
ApiService,
|
||||
OrgGraphsService,
|
||||
OrgSnippetsService,
|
||||
CustGraphsService,
|
||||
CustSnippetsService,
|
||||
CustPiesService,
|
||||
OrgPiesService,
|
||||
{
|
||||
provide: LocationStrategy,
|
||||
useClass: HashLocationStrategy
|
||||
|
@ -72,4 +92,10 @@ import { DashboardModule } from './dashboard/dashboard.module';
|
|||
],
|
||||
bootstrap: [ AppComponent ]
|
||||
})
|
||||
export class AppModule { }
|
||||
export class AppModule {
|
||||
constructor () {
|
||||
if (environment.enableAnalytics) {
|
||||
(<any>window).ga('create', environment.analyticsKey, 'auto');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core';
|
|||
import { Validators, FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { ApiService } from '../providers/api-service';
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
import 'rxjs/add/operator/map';
|
||||
|
||||
|
||||
@Component({
|
||||
templateUrl: 'login.component.html',
|
||||
|
@ -40,15 +40,11 @@ export class LoginComponent implements OnInit {
|
|||
}
|
||||
|
||||
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 => {
|
||||
|
|
|
@ -106,6 +106,7 @@
|
|||
<option value='R'>Arts, Entertainment & Recreation</option>
|
||||
<option value='S'>Other Service Activities</option>
|
||||
<option value='T'>Household Domestic Business</option>
|
||||
<option value='U'>Extraterritorial Organisations and Bodies</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Validators, FormBuilder, FormGroup } from '@angular/forms';
|
|||
import { ValidationManager } from 'ng2-validation-manager';
|
||||
import { ApiService } from '../providers/api-service';
|
||||
import {Router } from '@angular/router';
|
||||
import 'rxjs/add/operator/map';
|
||||
|
||||
|
||||
@Component({
|
||||
templateUrl: 'register.component.html',
|
||||
|
@ -78,24 +78,18 @@ export class RegisterComponent {
|
|||
.register(data)
|
||||
.subscribe(
|
||||
result => {
|
||||
console.log('registered!');
|
||||
this.registerStatus = 'success';
|
||||
console.log(this.registerStatus);
|
||||
this.router.navigate(['/dashboard']);
|
||||
},
|
||||
error => {
|
||||
console.log('Register Error');
|
||||
console.log(error);
|
||||
try {
|
||||
console.log(error.error);
|
||||
const jsonError = error.json();
|
||||
console.log('boop');
|
||||
this.registerStatusError = '"' + jsonError.error + '" Error, ' + jsonError.message;
|
||||
this.registerStatusError = '"' + error.error.error + '" Error, ' + error.error.message;
|
||||
} catch (e) {
|
||||
this.registerStatusError = 'There was a server error, please try again later.';
|
||||
}
|
||||
this.registerStatus = 'send_failed';
|
||||
console.log(this.registerStatus);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -122,24 +116,17 @@ export class RegisterComponent {
|
|||
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('Register Error');
|
||||
console.log(error);
|
||||
try {
|
||||
console.log(error.error);
|
||||
const jsonError = error.json();
|
||||
console.log('boop');
|
||||
this.registerStatusError = '"' + jsonError.error + '" Error, ' + jsonError.message;
|
||||
this.registerStatusError = '"' + error.error.error + '" Error, ' + error.error.message;
|
||||
} catch (e) {
|
||||
this.registerStatusError = 'There was a server error, please try again later.';
|
||||
}
|
||||
|
|
|
@ -99,6 +99,7 @@
|
|||
<option value='R'>Arts, Entertainment & Recreation</option>
|
||||
<option value='S'>Other Service Activities</option>
|
||||
<option value='T'>Household Domestic Business</option>
|
||||
<option value='U'>Extraterritorial Organisations and Bodies</option>
|
||||
</select>
|
||||
<span class="help-block">Alter this if your business sector has changed.</span>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { Validators, FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { ApiService } from '../providers/api-service';
|
||||
import 'rxjs/add/operator/map';
|
||||
|
||||
|
||||
@Component({
|
||||
templateUrl: 'account-edit.component.html',
|
||||
|
@ -105,23 +105,17 @@ export class AccountEditComponent implements OnInit {
|
|||
.accountEditUpdate(submitData)
|
||||
.subscribe(
|
||||
result => {
|
||||
console.log('data submitted!');
|
||||
this.submitStatus = 'success';
|
||||
console.log(this.submitStatus);
|
||||
},
|
||||
error => {
|
||||
console.log('Edit Error');
|
||||
console.log(error);
|
||||
try {
|
||||
console.log(error.error);
|
||||
const jsonError = error.json();
|
||||
console.log('boop');
|
||||
this.submitStatusError = '"' + jsonError.error + '" Error, ' + jsonError.message;
|
||||
this.submitStatusError = '"' + error.error.error + '" Error, ' + error.error.message;
|
||||
} catch (e) {
|
||||
this.submitStatusError = 'There was a server error, please try again later.';
|
||||
}
|
||||
this.submitStatus = 'send_failed';
|
||||
console.log(this.submitStatus);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -131,7 +125,6 @@ export class AccountEditComponent implements OnInit {
|
|||
if (!this.settingForm.valid && !this.settingCustomerForm.valid) {
|
||||
console.log('Not Valid!');
|
||||
this.submitStatus = 'validation_failed';
|
||||
console.log(this.submitStatus);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,74 @@
|
|||
<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">Essential Purchase</label>
|
||||
<div class="col-md-9">
|
||||
<div class="input-group">
|
||||
<input type="checkbox" class="mr-auto" [(ngModel)]="essentialPurchase" (ngModelChange)="transactionFormValidate()">
|
||||
<span class="help-block">Tick if the purchase is deemed an essential purchase for budgeting purposes.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-md-3 form-control-label" for="text-input">Recurring Purchase</label>
|
||||
<div class="col-md-9">
|
||||
<div class="input-group">
|
||||
<input type="checkbox" class="mr-auto" [(ngModel)]="recurringPurchase" (ngModelChange)="transactionFormValidate()">
|
||||
<span class="help-block">Tick if the purchase frequently recurs, such as monthly.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="recurringPurchase" class="form-group row">
|
||||
<label class="col-md-3 form-control-label" for="text-input"><strong>Recurring Period</strong></label>
|
||||
<div class="col-md-9">
|
||||
<div class="row">
|
||||
<div class="col-md-6 btn-group-vertical">
|
||||
<label class="btn btn-secondary mb-0" [class.active]="recurringType == 'daily'">
|
||||
<input value="daily" type="radio" name="radios" style="display:none;" [(ngModel)]="recurringType" (ngModelChange)="transactionFormValidate()">Daily
|
||||
</label>
|
||||
<label class="btn btn-secondary mb-0" [class.active]="recurringType == 'weekly'">
|
||||
<input value="weekly" type="radio" name="radios" style="display:none;" [(ngModel)]="recurringType" (ngModelChange)="transactionFormValidate()">Weekly
|
||||
</label>
|
||||
<label class="btn btn-secondary mb-0" [class.active]="recurringType == 'fortnightly'">
|
||||
<input value="fortnightly" type="radio" name="radios" style="display:none;" [(ngModel)]="recurringType" (ngModelChange)="transactionFormValidate()">Fortnightly
|
||||
</label>
|
||||
<label class="btn btn-secondary mb-0" [class.active]="recurringType == 'monthly'">
|
||||
<input value="monthly" type="radio" name="radios" style="display:none;" [(ngModel)]="recurringType" (ngModelChange)="transactionFormValidate()">Monthly
|
||||
</label>
|
||||
<label class="btn btn-secondary mb-0" [class.active]="recurringType == 'quarterly'">
|
||||
<input value="quarterly" type="radio" name="radios" style="display:none;" [(ngModel)]="recurringType" (ngModelChange)="transactionFormValidate()">Quarterly
|
||||
</label>
|
||||
<label class="btn btn-secondary mb-0" [class.active]="recurringType == 'yearly'">
|
||||
<input value="yearly" type="radio" name="radios" style="display:none;" [(ngModel)]="recurringType" (ngModelChange)="transactionFormValidate()">Yearly
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<span class="help-block">Please give the period of time the purchase will recur from "Time of Transaction".</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-md-3 form-control-label" for="text-input">Budget Type</label>
|
||||
<div class="col-md-9">
|
||||
<div class="row">
|
||||
<div class="col-md-6 btn-group-vertical">
|
||||
<label class="btn btn-secondary mb-0" [class.active]="categoryId == null">
|
||||
<input value="" type="radio" name="radios" style="display:none;" [(ngModel)]="categoryId">Uncategorised
|
||||
</label>
|
||||
<label *ngFor="let category of leftCategoryList" class="btn btn-secondary mb-0" [class.active]="categoryId == category">
|
||||
<input [value]="category" type="radio" name="radios" style="display:none;" [(ngModel)]="categoryId">{{ categoryList[category] }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-md-6 btn-group-vertical">
|
||||
<label *ngFor="let category2 of rightCategoryList" class="btn btn-secondary mb-0" [class.active]=" categoryId == category2">
|
||||
<input [value]="category2" type="radio" name="radios" style="display:none;" [(ngModel)]="categoryId">{{ categoryList[category2] }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<span class="help-block"><strong>Optional:</strong> Choose the Budget Type for the majority of the purchase.</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">
|
||||
|
@ -34,21 +102,21 @@
|
|||
<org-table *ngIf="storeList.length > 0" [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>
|
||||
<label class="col-md-3 form-control-label" for="text-input">Organisation Street Name</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>
|
||||
<label class="col-md-3 form-control-label" for="text-input">Organisation Town</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>
|
||||
<label class="col-md-3 form-control-label" for="text-input">Organisation Postcode</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>
|
||||
|
@ -89,14 +157,14 @@
|
|||
<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">
|
||||
<input type="number" class="form-control" formControlName="employee_amount" placeholder="0" min="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">
|
||||
<input type="number" class="form-control" formControlName="local_employee_amount" placeholder="0" min="0">
|
||||
<span class="help-block">Enter the amount of employees that live locally to the organisation for the entry month.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Validators, FormBuilder, FormGroup } from '@angular/forms';
|
|||
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',
|
||||
|
@ -30,6 +30,9 @@ export class AddDataComponent implements OnInit {
|
|||
organisationTown: string;
|
||||
organisationPostcode: string;
|
||||
amount: number;
|
||||
essentialPurchase = false;
|
||||
recurringPurchase = false;
|
||||
recurringType: string;
|
||||
transactionAdditionType = 1;
|
||||
storeList = [];
|
||||
showAddStore = false;
|
||||
|
@ -37,6 +40,11 @@ export class AddDataComponent implements OnInit {
|
|||
transactionFormInvalid = true;
|
||||
myDate: any;
|
||||
minDate: any;
|
||||
categoryList: any;
|
||||
categoryIdList: any;
|
||||
leftCategoryList: number[] = [];
|
||||
rightCategoryList: string[] = [];
|
||||
categoryId: number;
|
||||
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
|
@ -64,6 +72,17 @@ export class AddDataComponent implements OnInit {
|
|||
});
|
||||
this.myDate = moment().format('YYYY-MM-DD[T]HH:mm');
|
||||
// this.myDate = new Date().toISOString().slice(0, 16);
|
||||
this.api.categoryList().subscribe(
|
||||
result => {
|
||||
this.categoryList = result.categories;
|
||||
this.categoryIdList = Object.keys(this.categoryList);
|
||||
this.setCategoryList(this.categoryIdList);
|
||||
},
|
||||
error => {
|
||||
console.log('Retrieval Error');
|
||||
console.log( error._body );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
@ -71,6 +90,12 @@ export class AddDataComponent implements OnInit {
|
|||
this.accountType = localStorage.getItem('usertype');
|
||||
}
|
||||
|
||||
private setCategoryList(data: any) {
|
||||
let halfLength = Math.floor(data.length / 2);
|
||||
this.leftCategoryList = data.splice(0, halfLength);
|
||||
this.rightCategoryList = data;
|
||||
}
|
||||
|
||||
getMinDate() {
|
||||
// gets the April 1st date of the current year
|
||||
const aprilDate = moment().month(3).date(1);
|
||||
|
@ -149,12 +174,16 @@ export class AddDataComponent implements OnInit {
|
|||
}
|
||||
|
||||
transactionFormValidate() {
|
||||
if (this.submitOrg.name.length === 0 ||
|
||||
this.submitOrg.town.length === 0 ||
|
||||
this.amount === 0 ) {
|
||||
this.transactionFormInvalid = true;
|
||||
} else {
|
||||
this.transactionFormStatus = null;
|
||||
if (this.submitOrg.name.length &&
|
||||
this.amount &&
|
||||
(this.recurringPurchase &&
|
||||
this.recurringType ||
|
||||
!this.recurringPurchase &&
|
||||
!this.recurringType)) {
|
||||
this.transactionFormInvalid = false;
|
||||
} else {
|
||||
this.transactionFormInvalid = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,6 +199,9 @@ export class AddDataComponent implements OnInit {
|
|||
transaction_value : this.amount,
|
||||
purchase_time : purchaseTime,
|
||||
organisation_id : this.organisationId,
|
||||
category : this.categoryId,
|
||||
essential : this.essentialPurchase,
|
||||
recurring : this.recurringType,
|
||||
};
|
||||
break;
|
||||
case 2:
|
||||
|
@ -178,6 +210,9 @@ export class AddDataComponent implements OnInit {
|
|||
transaction_value : this.amount,
|
||||
purchase_time : purchaseTime,
|
||||
organisation_id : this.organisationId,
|
||||
category : this.categoryId,
|
||||
essential : this.essentialPurchase,
|
||||
recurring : this.recurringType,
|
||||
};
|
||||
break;
|
||||
case 3:
|
||||
|
@ -189,6 +224,9 @@ export class AddDataComponent implements OnInit {
|
|||
street_name : this.submitOrg.street_name,
|
||||
town : this.submitOrg.town,
|
||||
postcode : this.submitOrg.postcode,
|
||||
category : this.categoryId,
|
||||
essential : this.essentialPurchase,
|
||||
recurring : this.recurringType,
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
@ -199,31 +237,22 @@ export class AddDataComponent implements OnInit {
|
|||
.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);
|
||||
const jsonError = error.json();
|
||||
console.log('boop');
|
||||
this.transactionFormStatusError = '"' + jsonError.error + '" Error, ' + jsonError.message;
|
||||
this.transactionFormStatusError = '"' + error.error.error + '" Error, ' + error.error.message;
|
||||
} catch (e) {
|
||||
this.transactionFormStatusError = 'There was a server error, please try again later.';
|
||||
}
|
||||
this.transactionFormStatus = 'send_failed';
|
||||
console.log(this.transactionFormStatus);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -239,6 +268,9 @@ export class AddDataComponent implements OnInit {
|
|||
this.amount = null;
|
||||
this.transactionFormInvalid = true;
|
||||
this.showAddStore = false;
|
||||
this.essentialPurchase = false;
|
||||
this.recurringPurchase = false;
|
||||
this.recurringType = null;
|
||||
}
|
||||
|
||||
onSubmitPayroll() {
|
||||
|
@ -248,14 +280,11 @@ export class AddDataComponent implements OnInit {
|
|||
.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);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -267,14 +296,10 @@ export class AddDataComponent implements OnInit {
|
|||
.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);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -286,14 +311,10 @@ export class AddDataComponent implements OnInit {
|
|||
.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);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
172
src/app/dashboard/category-month.component.html
Normal file
172
src/app/dashboard/category-month.component.html
Normal file
|
@ -0,0 +1,172 @@
|
|||
<div class="animated fadeIn">
|
||||
<div class=row>
|
||||
<div *ngIf="weekList1" class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-block">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h4 class="card-title float-left mb-0">Purchases Last Week</h4>
|
||||
</div><!--/.col-->
|
||||
</div><!--/.row-->
|
||||
<div class="chart-wrapper">
|
||||
<ul *ngIf="weekList1" class="horizontal-bars type-2">
|
||||
<li *ngIf="weekEssential1">
|
||||
<span class="title">Essential Purchases</span>
|
||||
<span class="value">{{ ( weekEssential1 ? weekEssential1.value : 0 ) | currency:'GBP':'symbol':'1.2-2' }} <span class="text-muted small">
|
||||
({{ ( weekEssential1 ? weekEssential1.value : 0 ) / weekListValueSum1 | percent:'1.0-0' }})</span></span>
|
||||
<div class="bars">
|
||||
<div class="progress" style="height: 6px;">
|
||||
<div class="progress-bar bg-success" role="progressbar"
|
||||
[style.width]="(weekEssential1.value || 0 ) / weekListValueSum1 | percent:'1.0-0'" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li *ngFor="let categoryEntry of weekList1 | slice:0:categoryLimit1; let i=index;">
|
||||
<span class="title">{{ categoryEntry.category || 'Uncategorised' }}</span>
|
||||
<span class="value">{{ ( categoryEntry.value || 0 ) | currency:'GBP':'symbol':'1.2-2' }} <span class="text-muted small">
|
||||
({{ (categoryEntry.value || 0 ) / weekListValueSum1 | percent:'1.0-0' }})</span></span>
|
||||
<div class="bars">
|
||||
<div class="progress" style="height: 6px;">
|
||||
<div class="progress-bar bg-success" role="progressbar"
|
||||
[style.width]="(categoryEntry.value || 0 ) / weekListValueSum1 | percent:'1.0-0'" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<div *ngIf="weekList1">
|
||||
<li *ngIf="weekList1.length > categoryLimit1 && disableCategoryButton1 == false" class="divider text-center">
|
||||
<button type="button" class="btn btn-sm btn-link text-muted" (click)="loadMore1()"><i class="icon-options"></i></button>
|
||||
</li>
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!--/.col-->
|
||||
<div *ngIf="weekList2" class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-block">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h4 class="card-title float-left mb-0">Purchases 1 Week Ago</h4>
|
||||
</div><!--/.col-->
|
||||
</div><!--/.row-->
|
||||
<div class="chart-wrapper">
|
||||
<ul *ngIf="weekList2" class="horizontal-bars type-2">
|
||||
<li *ngIf="weekEssential2">
|
||||
<span class="title">Essential Purchases</span>
|
||||
<span class="value">{{ ( weekEssential2 ? weekEssential2.value : 0 ) | currency:'GBP':'symbol':'1.2-2' }} <span class="text-muted small">
|
||||
({{ ( weekEssential2 ? weekEssential2.value : 0 ) / weekListValueSum2 | percent:'1.0-0' }})</span></span>
|
||||
<div class="bars">
|
||||
<div class="progress" style="height: 6px;">
|
||||
<div class="progress-bar bg-success" role="progressbar"
|
||||
[style.width]="(weekEssential2.value || 0 ) / weekListValueSum2 | percent:'1.0-0'" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li *ngFor="let categoryEntry of weekList2 | slice:0:categoryLimit2; let i=index;">
|
||||
<span class="title">{{ categoryEntry.category || 'Uncategorised' }}</span>
|
||||
<span class="value">{{ ( categoryEntry.value || 0 ) | currency:'GBP':'symbol':'1.2-2' }} <span class="text-muted small">
|
||||
({{ (categoryEntry.value || 0 ) / weekListValueSum2 | percent:'1.0-0' }})</span></span>
|
||||
<div class="bars">
|
||||
<div class="progress" style="height: 6px;">
|
||||
<div class="progress-bar bg-success" role="progressbar"
|
||||
[style.width]="(categoryEntry.value || 0 ) / weekListValueSum2 | percent:'1.0-0'" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<div *ngIf="weekList2">
|
||||
<li *ngIf="weekList2.length > categoryLimit2 && disableCategoryButtonFirst == false" class="divider text-center">
|
||||
<button type="button" class="btn btn-sm btn-link text-muted" (click)="loadMore2()"><i class="icon-options"></i></button>
|
||||
</li>
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!--/.col-->
|
||||
<div *ngIf="weekList3" class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-block">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h4 class="card-title float-left mb-0">Purchases 2 Weeks Ago</h4>
|
||||
</div><!--/.col-->
|
||||
</div><!--/.row-->
|
||||
<div class="chart-wrapper">
|
||||
<ul *ngIf="weekList3" class="horizontal-bars type-2">
|
||||
<li *ngIf="weekEssential3">
|
||||
<span class="title">Essential Purchases</span>
|
||||
<span class="value">{{ ( weekEssential3 ? weekEssential3.value : 0 ) | currency:'GBP':'symbol':'1.2-2' }} <span class="text-muted small">
|
||||
({{ ( weekEssential3 ? weekEssential3.value : 0 ) / weekListValueSum3 | percent:'1.0-0' }})</span></span>
|
||||
<div class="bars">
|
||||
<div class="progress" style="height: 6px;">
|
||||
<div class="progress-bar bg-success" role="progressbar"
|
||||
[style.width]="(weekEssential3.value || 0 ) / weekListValueSum3 | percent:'1.0-0'" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li *ngFor="let categoryEntry of weekList3 | slice:0:categoryLimit3; let i=index;">
|
||||
<span class="title">{{ categoryEntry.category || 'Uncategorised' }}</span>
|
||||
<span class="value">{{ ( categoryEntry.value || 0 ) | currency:'GBP':'symbol':'1.2-2' }} <span class="text-muted small">
|
||||
({{ (categoryEntry.value || 0 ) / weekListValueSum3 | percent:'1.0-0' }})</span></span>
|
||||
<div class="bars">
|
||||
<div class="progress" style="height: 6px;">
|
||||
<div class="progress-bar bg-success" role="progressbar"
|
||||
[style.width]="(categoryEntry.value || 0 ) / weekListValueSum3 | percent:'1.0-0'" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<div *ngIf="weekList3">
|
||||
<li *ngIf="weekList3.length > categoryLimit3 && disableCategoryButtonFirst == false" class="divider text-center">
|
||||
<button type="button" class="btn btn-sm btn-link text-muted" (click)="loadMore3()"><i class="icon-options"></i></button>
|
||||
</li>
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!--/.col-->
|
||||
<div *ngIf="weekList4" class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-block">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h4 class="card-title float-left mb-0">Purchases 3 Weeks Ago</h4>
|
||||
</div><!--/.col-->
|
||||
</div><!--/.row-->
|
||||
<div class="chart-wrapper">
|
||||
<ul *ngIf="weekList4" class="horizontal-bars type-2">
|
||||
<li *ngIf="weekEssential4">
|
||||
<span class="title">Essential Purchases</span>
|
||||
<span class="value">{{ ( weekEssential4 ? weekEssential4.value : 0 ) | currency:'GBP':'symbol':'1.2-2' }} <span class="text-muted small">
|
||||
({{ ( weekEssential4 ? weekEssential4.value : 0 ) / weekListValueSum4 | percent:'1.0-0' }})</span></span>
|
||||
<div class="bars">
|
||||
<div class="progress" style="height: 6px;">
|
||||
<div class="progress-bar bg-success" role="progressbar"
|
||||
[style.width]="(weekEssential4.value || 0 ) / weekListValueSum4 | percent:'1.0-0'" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li *ngFor="let categoryEntry of weekList4 | slice:0:categoryLimit4; let i=index;">
|
||||
<span class="title">{{ categoryEntry.category || 'Uncategorised' }}</span>
|
||||
<span class="value">{{ ( categoryEntry.value || 0 ) | currency:'GBP':'symbol':'1.2-2' }} <span class="text-muted small">
|
||||
({{ (categoryEntry.value || 0 ) / weekListValueSum4 | percent:'1.0-0' }})</span></span>
|
||||
<div class="bars">
|
||||
<div class="progress" style="height: 6px;">
|
||||
<div class="progress-bar bg-success" role="progressbar"
|
||||
[style.width]="(categoryEntry.value || 0 ) / weekListValueSum4 | percent:'1.0-0'" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<div *ngIf="weekList4">
|
||||
<li *ngIf="weekList4.length > categoryLimit4 && disableCategoryButtonFirst == false" class="divider text-center">
|
||||
<button type="button" class="btn btn-sm btn-link text-muted" (click)="loadMore4()"><i class="icon-options"></i></button>
|
||||
</li>
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!--/.col-->
|
||||
</div><!--/.row-->
|
||||
</div>
|
119
src/app/dashboard/category-month.component.ts
Normal file
119
src/app/dashboard/category-month.component.ts
Normal file
|
@ -0,0 +1,119 @@
|
|||
import { Directive, Component, OnInit } from '@angular/core';
|
||||
import { ApiService } from '../providers/api-service';
|
||||
import { DataType } from '../shared/data-types.enum';
|
||||
import * as moment from 'moment';
|
||||
|
||||
|
||||
@Component({
|
||||
templateUrl: 'category-month.component.html'
|
||||
})
|
||||
export class CategoryMonthComponent implements OnInit {
|
||||
|
||||
disableCategoryButton1: boolean = false;
|
||||
disableCategoryButton2: boolean = false;
|
||||
disableCategoryButton3: boolean = false;
|
||||
disableCategoryButton4: boolean = false;
|
||||
|
||||
weekPurchaseList = {
|
||||
first: 0,
|
||||
};
|
||||
|
||||
weekList1 = [];
|
||||
weekList2 = [];
|
||||
weekList3 = [];
|
||||
weekList4 = [];
|
||||
weekListValueSum1: number = 0;
|
||||
weekListValueSum2: number = 0;
|
||||
weekListValueSum3: number = 0;
|
||||
weekListValueSum4: number = 0;
|
||||
weekEssential1: number = 0;
|
||||
weekEssential2: number = 0;
|
||||
weekEssential3: number = 0;
|
||||
weekEssential4: number = 0;
|
||||
|
||||
dayList: any[] = [];
|
||||
valueList: number[] = [];
|
||||
myWeek1: any;
|
||||
myWeek2: any;
|
||||
myWeek3: any;
|
||||
myWeek4: any;
|
||||
categoryLimit1: number = 6;
|
||||
categoryLimit2: number = 6;
|
||||
categoryLimit3: number = 6;
|
||||
categoryLimit4: number = 6;
|
||||
|
||||
constructor(
|
||||
private api: ApiService,
|
||||
) {
|
||||
this.setDate();
|
||||
this.api.categoryTransactionList().subscribe(
|
||||
result => {
|
||||
this.setData(result);
|
||||
},
|
||||
error => {
|
||||
console.log('Retrieval Error');
|
||||
console.log( error._body );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
private setDate () {
|
||||
this.myWeek1 = moment().startOf('isoWeek').format('YYYY-MM-DD');
|
||||
this.myWeek2 = moment(this.myWeek1).subtract(1, 'weeks').format('YYYY-MM-DD');
|
||||
this.myWeek3 = moment(this.myWeek2).subtract(1, 'weeks').format('YYYY-MM-DD');
|
||||
this.myWeek4 = moment(this.myWeek3).subtract(1, 'weeks').format('YYYY-MM-DD');
|
||||
}
|
||||
|
||||
private setData (data: any) {
|
||||
function prop<T, K extends keyof T>(obj: T, key: K) {
|
||||
return obj[key];
|
||||
}
|
||||
this.weekList1 = prop(data.data.categories, this.myWeek1);
|
||||
this.weekList2 = prop(data.data.categories, this.myWeek2);
|
||||
this.weekList3 = prop(data.data.categories, this.myWeek3);
|
||||
this.weekList4 = prop(data.data.categories, this.myWeek4);
|
||||
this.getMaxValue(this.weekList1, this.weekList2, this.weekList3, this.weekList4);
|
||||
this.weekEssential1 = prop(data.data.essentials, this.myWeek1);
|
||||
this.weekEssential2 = prop(data.data.essentials, this.myWeek2);
|
||||
this.weekEssential3 = prop(data.data.essentials, this.myWeek3);
|
||||
this.weekEssential4 = prop(data.data.essentials, this.myWeek4);
|
||||
}
|
||||
|
||||
private getMaxValue (data1: any,
|
||||
data2: any,
|
||||
data3: any,
|
||||
data4: any) {
|
||||
if (data1) {
|
||||
this.weekListValueSum1 = data1.reduce(function (s, a) {return s + a.value;}, 0);
|
||||
}
|
||||
if (data2) {
|
||||
this.weekListValueSum2 = data2.reduce(function (s, a) {return s + a.value;}, 0);
|
||||
}
|
||||
if (data3) {
|
||||
this.weekListValueSum3 = data3.reduce(function (s, a) {return s + a.value;}, 0);
|
||||
}
|
||||
if (data4) {
|
||||
this.weekListValueSum4 = data4.reduce(function (s, a) {return s + a.value;}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private loadMore1 () {
|
||||
this.disableCategoryButton1 = true;
|
||||
this.categoryLimit1 = 20;
|
||||
}
|
||||
private loadMore2 () {
|
||||
this.disableCategoryButton2 = true;
|
||||
this.categoryLimit2 = 20;
|
||||
}
|
||||
private loadMore3 () {
|
||||
this.disableCategoryButton3 = true;
|
||||
this.categoryLimit3 = 20;
|
||||
}
|
||||
private loadMore4 () {
|
||||
this.disableCategoryButton4 = true;
|
||||
this.categoryLimit4 = 20;
|
||||
}
|
||||
}
|
|
@ -1,131 +1,115 @@
|
|||
<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':'symbol':'1.2-2' }}</strong>
|
||||
</li>
|
||||
<li>
|
||||
<div class="text-muted">Value to Local Economy</div>
|
||||
<strong>{{ basicStats.user_sum * 2.3 | currency:'GBP':'symbol':'1.2-2' }}</strong>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<snippet-bar-cust></snippet-bar-cust>
|
||||
<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':'symbol':'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':'symbol':'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':'symbol':'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':'symbol':'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':'symbol':'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':'symbol':'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':'symbol':'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':'symbol':'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 *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-->
|
||||
</div>
|
||||
<div class=row>
|
||||
<div class="col-xl-6">
|
||||
<panel-pie></panel-pie><!--All Purchases -->
|
||||
<!-- <div class="demo-container" ng-app="stacked-bar" ng-controller="stacked-bar">
|
||||
<div id="stacked-bar" dx-chart="chartOptions"></div>
|
||||
</div> -->
|
||||
</div><!--/.col-->
|
||||
<!--<div *ngIf="showCategoryDoughnutChart" class="col-xl-6">
|
||||
<div class="card"> -->
|
||||
<!-- <body style="background-color:rgb(0,0,0);"> -->
|
||||
<!-- <div class="card-block">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h4 class="card-title mb-0">Spending by Category</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart-wrapper">
|
||||
<canvas baseChart class="chart"
|
||||
[datasets]="doughnutChartDataCategory"
|
||||
[labels]="doughnutChartLabelsCategory"
|
||||
[options]="doughnutChartOptionsCategory"
|
||||
[colors]= "doughnutChartColoursCategory"
|
||||
[legend]="chartLegend"
|
||||
[chartType]="chartType"
|
||||
(chartHover)="chartHovered($event)"
|
||||
(chartClick)="chartClicked($event)"></canvas>
|
||||
</div>
|
||||
</div> -->
|
||||
<!-- </body> -->
|
||||
<!-- </div> --><!--/.col-->
|
||||
<div *ngIf="showEssentialBarChart" class="col-xl-6">
|
||||
<div class="card">
|
||||
<div class="card-block">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h4 class="card-title mb-0">No. of Essential Purchases</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart-wrapper">
|
||||
<canvas baseChart class="chart"
|
||||
[datasets]="barChartDataEssential"
|
||||
[labels]="barChartLabelsEssential"
|
||||
[options]="barChartOptionsEssential"
|
||||
[chartType]="barChartTypeEssential"
|
||||
(chartHover)="chartHovered($event)"
|
||||
(chartClick)="chartClicked($event)"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!--/.col-->
|
||||
<div class="col-xl-6">
|
||||
<div class="card">
|
||||
<div class="card-block">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h4 class="card-title float-left mb-0">Your Purchases by Category</h4>
|
||||
</div><!--/.col-->
|
||||
</div><!--/.row-->
|
||||
<div class="chart-wrapper">
|
||||
<canvas baseChart class="chart"
|
||||
[datasets]="barChartDataCategory"
|
||||
[labels]="barChartLabelsCategory"
|
||||
[options]="barChartOptionsCategory"
|
||||
[colors]="barChartColoursCategory"
|
||||
[legend]="barChartLegendCategory"
|
||||
[chartType]="barChartTypeCategory"
|
||||
(chartHover)="chartHovered($event)"
|
||||
(chartClick)="chartClicked($event)"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!--/.col-->
|
||||
<div class="col-xl-6">
|
||||
<div class="card">
|
||||
<div class="card-block">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h4 class="card-title float-left mb-0"> Global Puchases by Category</h4>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div *ngIf="showTotalCategoryList" class="chart-wrapper">
|
||||
<ul class="icons-list">
|
||||
<!-- New loop -->
|
||||
<li *ngFor="let category of totalCategoryList | slice:0:totalCategoryLimit; let i=index">
|
||||
<i [ngClass]="['icon-' + category.icon, getBootstrapColour(i)]"></i>
|
||||
<div class="desc">
|
||||
<div class="title">{{ category.category || 'N/A' }}</div>
|
||||
</div>
|
||||
<div class="value">
|
||||
<div class="small text-muted">Bought</div>
|
||||
<strong>{{ category.value || 'N/A' }}</strong>
|
||||
</div>
|
||||
</li>
|
||||
<li *ngIf="totalCategoryList.length > totalCategoryLimit && disableCategoryButton == false" class="divider text-center">
|
||||
<button type="button" class="btn btn-sm btn-link text-muted" (click)="categoryLoadMore()"><i class="icon-options"></i></button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div><!--/.row-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,16 +1,25 @@
|
|||
import { Directive, Component, OnInit } from '@angular/core';
|
||||
import { CurrencyPipe } from '@angular/common';
|
||||
import { ApiService } from '../providers/api-service';
|
||||
import { Router } from '@angular/router';
|
||||
import { ChartOptions, ChartType, ChartDataSets } from 'chart.js';
|
||||
import { GraphWidget } from '../widgets/graph-widget.component';
|
||||
import { Color, Label } from 'ng2-charts';
|
||||
import { CustBarSnippetComponent } from '../snippets/cust-snippet-bar.component';
|
||||
import { PiePanel } from '../panels/pie-panel.component';
|
||||
import { DataType } from '../shared/data-types.enum';
|
||||
import * as moment from 'moment';
|
||||
import { MoreStuffComponent } from '../dashboard/more-graphs-and-tables.component';
|
||||
// import { StackedBarChartComponent } from '../panels/stacked-bar.component';
|
||||
|
||||
interface SuppliersComponent {
|
||||
name : string;
|
||||
}
|
||||
|
||||
@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;
|
||||
|
@ -19,27 +28,178 @@ export class DashboardCustomerComponent implements OnInit {
|
|||
trends: any;
|
||||
myRank: any;
|
||||
username: any;
|
||||
maxPurchase: number = 0;
|
||||
|
||||
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,
|
||||
disableCategoryButton: boolean = false;
|
||||
|
||||
public bootstrapColours: string[] = ['bg-primary', 'bg-secondary', 'bg-success',
|
||||
'bg-danger', 'bg-warning', 'bg-info'];
|
||||
|
||||
public chartType = 'doughnut';
|
||||
public chartLegend = true;
|
||||
public doughnutChartDataCategory: any[] = [];
|
||||
public doughnutChartLabelsCategory: string[] = [];
|
||||
public doughnutChartColoursCategory: any[] = [
|
||||
{
|
||||
backgroundColor:[
|
||||
'#ffa1b5',
|
||||
'#3cde52',
|
||||
'#52afed',
|
||||
'#c133e3',
|
||||
'#f7fa08',
|
||||
'#75152d',
|
||||
'#ee12ee',
|
||||
'#15eaea',
|
||||
'#eaa015',
|
||||
'#ea1515',
|
||||
'#2d4fcc'
|
||||
]
|
||||
}];
|
||||
|
||||
public doughnutChartOptionsCategory:any = {
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
label: (tooltip, data) => {
|
||||
return this.tooltipLabelCallback(tooltip, data);
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
myWeek1: any;
|
||||
|
||||
weekList1 = [];
|
||||
|
||||
public purchaseNotEssential: number;
|
||||
public purchaseEssential: number;
|
||||
public showEssentialBarChart = false;
|
||||
public showCategoryBarChart = false;
|
||||
public showCategoryDoughnutChart = false;
|
||||
|
||||
public barChartDataEssential:any[]=[
|
||||
{data: 0, label: 'Essential', stack: '1'},
|
||||
{data: 0, label: 'Non-Essential', stack: '1'},
|
||||
];
|
||||
public barChartLabelsEssential:string[] = ['All Purchases'];
|
||||
public barChartOptionsEssential:any = {
|
||||
responsive: true,
|
||||
scales:{
|
||||
xAxes:[{
|
||||
scaleLabel: {
|
||||
display:true,
|
||||
},
|
||||
stacked:true,
|
||||
|
||||
}],
|
||||
}
|
||||
};
|
||||
public barChartTypeEssential:string = 'horizontalBar';
|
||||
|
||||
public barChartOptionsCategory:any = {
|
||||
scaleShowVerticalLines: false,
|
||||
responsive: true,
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
beginAtZero: true,
|
||||
callback: label => `£${label}`
|
||||
}
|
||||
}]
|
||||
},
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
label: (tooltip, data) => {
|
||||
return this.tooltipLabelCallback(tooltip, data);
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
public barChartTypeCategory:string = 'bar';
|
||||
public barChartLegendCategory:boolean = false;
|
||||
public barChartDataCategory:any[]=[];
|
||||
public barChartLabelsCategory:string[] = [];
|
||||
public barChartColoursCategory: any[] = [
|
||||
{
|
||||
backgroundColor:[
|
||||
'#ffa1b5',
|
||||
'#3cde52',
|
||||
'#52afed',
|
||||
'#c133e3',
|
||||
'#f7fa08',
|
||||
'#75152d',
|
||||
'#ee12ee',
|
||||
'#15eaea',
|
||||
'#eaa015',
|
||||
'#ea1515',
|
||||
'#2d4fcc'
|
||||
]
|
||||
}];
|
||||
|
||||
|
||||
weekPurchaseList = {
|
||||
first: 0,
|
||||
second: 0,
|
||||
max: 0,
|
||||
sum: 0,
|
||||
count: 0,
|
||||
};
|
||||
|
||||
showTotalCategoryList: boolean = false;
|
||||
totalCategoryLimit: number = 10;
|
||||
totalCategoryList: any[]=[];
|
||||
|
||||
|
||||
// Graph widgets
|
||||
public widgetList = [
|
||||
{
|
||||
type: 'graph',
|
||||
name: 'total_last_week',
|
||||
icon: 'icon-diamond',
|
||||
title: 'Last Week Total',
|
||||
dataType: DataType.currency,
|
||||
},
|
||||
{
|
||||
type: 'graph',
|
||||
name: 'avg_spend_last_week',
|
||||
icon: 'icon-diamond',
|
||||
title: 'Last Week Avg. Spend',
|
||||
dataType: DataType.currency,
|
||||
},
|
||||
{
|
||||
type: 'graph',
|
||||
name: 'total_last_month',
|
||||
title: 'Last Month Total',
|
||||
dataType: DataType.currency,
|
||||
},
|
||||
{
|
||||
type: 'graph',
|
||||
name: 'avg_spend_last_month',
|
||||
title: 'Last Month Avg. Spend',
|
||||
dataType: DataType.currency,
|
||||
},
|
||||
];
|
||||
|
||||
constructor(
|
||||
private api: ApiService,
|
||||
private currencyPipe: CurrencyPipe,
|
||||
) {
|
||||
this.api.basicStats().subscribe(
|
||||
this.setDate();
|
||||
this.api.customerStats().subscribe(
|
||||
result => {
|
||||
this.basicStats = result;
|
||||
this.setWeekPurchaseList(result.weeks);
|
||||
this.setWeekData(result);
|
||||
this.setChartData(result.data.cat_total);
|
||||
this.totalCategoryList = result.data.cat_list;
|
||||
if (this.totalCategoryList) {
|
||||
this.showTotalCategoryList = true;
|
||||
}
|
||||
this.purchaseEssential = result.data.essentials.purchase_no_essential_total;
|
||||
this.purchaseNotEssential = result.data.essentials.purchase_no_total - this.purchaseEssential;
|
||||
this.barChartDataEssential = [
|
||||
{data: [this.purchaseEssential], label: 'Essential', stack: '1'},
|
||||
{data: [this.purchaseNotEssential], label: 'Non-Essential', stack: '1'},
|
||||
];
|
||||
this.showEssentialBarChart = true;
|
||||
},
|
||||
error => {
|
||||
console.log('Retrieval Error');
|
||||
|
@ -48,6 +208,77 @@ export class DashboardCustomerComponent implements OnInit {
|
|||
);
|
||||
}
|
||||
|
||||
private setChartData(dataCat: any) {
|
||||
this.barChartLabelsCategory = Object.keys(dataCat);
|
||||
let barChartDataCategoryInitial = Object.keys(dataCat).map(key => dataCat[key]);
|
||||
this.barChartDataCategory = [
|
||||
{data: barChartDataCategoryInitial, label: 'Series A'},
|
||||
];
|
||||
this.showCategoryBarChart = true;
|
||||
if (this.weekList1) {
|
||||
let doughnutChartDataCategoryInitial = this.weekList1.map(function(a) {return a.value;});
|
||||
this.doughnutChartDataCategory = [
|
||||
{data: doughnutChartDataCategoryInitial, label: 'Series A'},
|
||||
];
|
||||
// setTimeout is currently a workaround for ng2-charts labels
|
||||
setTimeout(() => this.doughnutChartLabelsCategory = this.weekList1.map(function(a) {return a.category;}), 0);
|
||||
this.showCategoryDoughnutChart = true;
|
||||
}
|
||||
}
|
||||
|
||||
private setDate () {
|
||||
this.myWeek1 = moment().startOf('isoWeek').format('YYYY-MM-DD');
|
||||
}
|
||||
|
||||
private setWeekData (data: any) {
|
||||
function prop<T, K extends keyof T>(obj: T, key: K) {
|
||||
return obj[key];
|
||||
}
|
||||
this.weekList1 = prop(data.data.categories, this.myWeek1);
|
||||
}
|
||||
|
||||
public setWeekPurchaseList (data: any) {
|
||||
this.weekPurchaseList = {
|
||||
first: data.first,
|
||||
second: data.second,
|
||||
max: data.max,
|
||||
sum: data.sum,
|
||||
count: data.count,
|
||||
};
|
||||
}
|
||||
|
||||
private categoryLoadMore () {
|
||||
this.disableCategoryButton = true;
|
||||
this.totalCategoryLimit = 30;
|
||||
}
|
||||
|
||||
public getBootstrapColour(index: number) {
|
||||
return this.bootstrapColours[index % this.bootstrapColours.length];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private tooltipLabelCallback(tooltipItem: any, data: any) {
|
||||
var dataset = data.datasets[tooltipItem.datasetIndex];
|
||||
var value = dataset.data[tooltipItem.index];
|
||||
return this.currencyPipe.transform(value, 'GBP', 'symbol', '1.2-2');
|
||||
}
|
||||
|
||||
// events
|
||||
public chartClicked(e: any): void {
|
||||
}
|
||||
|
||||
public chartHovered(e: any): void {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
<div class="animated fadeIn">
|
||||
<snippet-bar-org></snippet-bar-org>
|
||||
<div class="row">
|
||||
|
@ -6,8 +7,107 @@
|
|||
[graphName]="widget.name"
|
||||
[graphTitle]="widget.title"
|
||||
[graphIcon]="widget.icon"
|
||||
[dataType]="widget.dataType"></widget-graph>
|
||||
[dataType]="widget.dataType">
|
||||
</widget-graph>
|
||||
</div><!--/.col-->
|
||||
</div><!--/.row-->
|
||||
<panel-graph></panel-graph>
|
||||
</div>
|
||||
<div class=row>
|
||||
<div class="col-xl-6">
|
||||
<div class="card">
|
||||
<div class="card-block">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h4 class="card-title mb-0">Number of Essential Purchases</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="showEssentialBarChart" class="chart-wrapper">
|
||||
<canvas baseChart class="chart"
|
||||
[datasets]="barChartDataEssential"
|
||||
[labels]="barChartLabelsEssential"
|
||||
[options]="barChartOptionsEssential"
|
||||
[chartType]="barChartTypeEssential"
|
||||
(chartHover)="chartHovered($event)"
|
||||
(chartClick)="chartClicked($event)"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!--/.col-->
|
||||
<div class="col-xl-6">
|
||||
<div class="card">
|
||||
<div class="card-block">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h4 class="card-title float-left mb-0">All Organisation Purchases by Category</h4>
|
||||
</div><!--/.col-->
|
||||
</div><!--/.row-->
|
||||
<div class="chart-wrapper">
|
||||
<canvas baseChart class="chart"
|
||||
[datasets]="barChartDataCategory"
|
||||
[labels]="barChartLabelsCategory"
|
||||
[options]="barChartOptionsCategory"
|
||||
[colors]="barChartColoursCategory"
|
||||
[legend]="barChartLegendCategory"
|
||||
[chartType]="barChartTypeCategory"
|
||||
(chartHover)="chartHovered($event)"
|
||||
(chartClick)="chartClicked($event)"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!--/.col-->
|
||||
<div *ngIf="showCategoryDoughnutChart" class="col-xl-6">
|
||||
<div class="card">
|
||||
<div class="card-block">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h4 class="card-title mb-0">This weeks' spending by Category</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart-wrapper">
|
||||
<canvas baseChart class="chart"
|
||||
[datasets]="doughnutChartDataCategory"
|
||||
[labels]="doughnutChartLabelsCategory"
|
||||
[options]="doughnutChartOptionsCategory"
|
||||
[colors]="doughnutChartColoursCategory"
|
||||
[legend]="chartLegend"
|
||||
[chartType]="chartType"
|
||||
(chartHover)="chartHovered($event)"
|
||||
(chartClick)="chartClicked($event)"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6">
|
||||
<org-pie-panel></org-pie-panel>
|
||||
</div>
|
||||
<div class="col-xl-6">
|
||||
<div class="card">
|
||||
<div class="card-block">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h4 class="card-title float-left mb-0"> Global Puchases by Category</h4>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div *ngIf="showTotalCategoryList" class="chart-wrapper">
|
||||
<ul class="icons-list">
|
||||
<!-- New loop -->
|
||||
<li *ngFor="let category of totalCategoryList | slice:0:totalCategoryLimit; let i=index">
|
||||
<i [ngClass]="['icon-' + category.icon, getBootstrapColour(i)]"></i>
|
||||
<div class="desc">
|
||||
<div class="title">{{ category.category || 'N/A' }}</div>
|
||||
</div>
|
||||
<div class="value">
|
||||
<div class="small text-muted">Bought</div>
|
||||
<strong>{{ category.value || 'N/A' }}</strong>
|
||||
</div>
|
||||
</li>
|
||||
<li *ngIf="totalCategoryList.length > totalCategoryLimit && disableCategoryButton == false" class="divider text-center">
|
||||
<button type="button" class="btn btn-sm btn-link text-muted" (click)="categoryLoadMore()"><i class="icon-options"></i></button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div><!--/.row-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { Router, NavigationEnd } from "@angular/router";
|
||||
import { CurrencyPipe } from '@angular/common';
|
||||
import { ChartOptions, ChartType, ChartDataSets } from 'chart.js';
|
||||
import { Color, Label } from 'ng2-charts';
|
||||
import { GraphWidget } from '../widgets/graph-widget.component';
|
||||
import { OrgBarSnippetComponent } from '../snippets/org-snippet-bar.component';
|
||||
import { GraphPanel } from '../panels/graph-panel.component';
|
||||
import { OrgPiePanel } from '../panels/org-pie-panel.component';
|
||||
import { DataType } from '../shared/data-types.enum';
|
||||
import { ApiService } from '../providers/api-service';
|
||||
import { environment } from '../../environments/environment';
|
||||
import * as moment from 'moment';
|
||||
|
||||
@Component({
|
||||
templateUrl: 'dashboard.component.html'
|
||||
|
@ -37,6 +44,13 @@ export class DashboardComponent {
|
|||
title: 'Sales Last 30 Days',
|
||||
dataType: DataType.currency,
|
||||
},
|
||||
{
|
||||
type: 'graph',
|
||||
name: 'sales_last_quart',
|
||||
icon: 'icon-diamond',
|
||||
title: 'Sales Last Quart',
|
||||
dataType: DataType.currency,
|
||||
},
|
||||
{
|
||||
type: 'graph',
|
||||
name: 'purchases_last_7_days',
|
||||
|
@ -49,7 +63,307 @@ export class DashboardComponent {
|
|||
title: 'Purchases Last 30 Days',
|
||||
dataType: DataType.currency,
|
||||
},
|
||||
{
|
||||
type: 'graph',
|
||||
name: 'purchases_last_quart;',
|
||||
title: 'Purchases Last Quart',
|
||||
dataType: DataType.currency,
|
||||
},
|
||||
];
|
||||
|
||||
constructor() { }
|
||||
disableCategoryButton: boolean = false;
|
||||
|
||||
public bootstrapColours: string[] = ['bg-primary', 'bg-secondary', 'bg-success',
|
||||
'bg-danger', 'bg-warning', 'bg-info'];
|
||||
|
||||
public chartType = 'doughnut';
|
||||
public chartLegend = true;
|
||||
public doughnutChartDataCategory: any[] = [];
|
||||
public doughnutChartLabelsCategory: string[] = [];
|
||||
public doughnutChartColoursCategory: any[] = [
|
||||
{
|
||||
backgroundColor:[
|
||||
'#ffa1b5',
|
||||
'#3cde52',
|
||||
'#52afed',
|
||||
'#c133e3',
|
||||
'#f7fa08',
|
||||
'#75152d',
|
||||
'#ee12ee',
|
||||
'#15eaea',
|
||||
'#eaa015',
|
||||
'#ea1515',
|
||||
'#2d4fcc'
|
||||
]
|
||||
}];
|
||||
|
||||
|
||||
public doughnutChartOptionsCategory:any = {
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
label: (tooltip, data) => {
|
||||
return this.tooltipLabelCallback(tooltip, data);
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
myWeek1: any;
|
||||
|
||||
weekList1 = [];
|
||||
|
||||
public purchaseNotEssential: number;
|
||||
public purchaseEssential: number;
|
||||
public showEssentialBarChart:boolean = false;
|
||||
public showCategoryBarChart = false;
|
||||
public showCategoryDoughnutChart = false;
|
||||
|
||||
public barChartDataEssential: ChartDataSets[] = [
|
||||
{data: [0], label: 'Essential', stack: '1'},
|
||||
{data: [0], label: 'Non-Essential', stack: '1'},
|
||||
];
|
||||
public barChartLabelsEssential:string[] = ['All Purchases'];
|
||||
public barChartOptionsEssential:any = {
|
||||
responsive: true,
|
||||
scales:{
|
||||
xAxes:[{
|
||||
stacked:true
|
||||
}],
|
||||
yAxes:[{
|
||||
stacked:true
|
||||
}]
|
||||
}
|
||||
};
|
||||
public barChartTypeEssential:string = 'horizontalBar';
|
||||
public barChartColoursCategory: any[] = [
|
||||
{
|
||||
backgroundColor:[
|
||||
'#ffa1b5',
|
||||
'#3cde52',
|
||||
'#52afed',
|
||||
'#c133e3',
|
||||
'#f7fa08',
|
||||
'#75152d',
|
||||
'#ee12ee',
|
||||
'#15eaea',
|
||||
'#eaa015',
|
||||
'#ea1515',
|
||||
'#2d4fcc'
|
||||
]
|
||||
}];
|
||||
|
||||
public barChartOptionsCategory:any = {
|
||||
scaleShowVerticalLines: false,
|
||||
responsive: true,
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
beginAtZero: true,
|
||||
callback: label => `£${label}`
|
||||
}
|
||||
}]
|
||||
},
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
label: (tooltip, data) => {
|
||||
return this.tooltipLabelCallback(tooltip, data);
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
public barChartTypeCategory:string = 'bar';
|
||||
public barChartLegendCategory:boolean = false;
|
||||
public barChartDataCategory:any[]=[];
|
||||
public barChartLabelsCategory:string[] = [];
|
||||
|
||||
public lineChartDataSector: ChartDataSets[] = [
|
||||
{ data: [], label: '' },
|
||||
];
|
||||
public lineChartLabelsSector: Label[] = ['January', 'February', 'March', 'April', 'May', 'June', 'July','August','September','October','November','December'];
|
||||
public lineChartOptionsSector: (ChartOptions & { annotation: any }) = {
|
||||
responsive: true,
|
||||
scales: {
|
||||
// We use this empty structure as a placeholder for dynamic theming.
|
||||
xAxes: [{}],
|
||||
yAxes: [{}]
|
||||
},
|
||||
annotation: {
|
||||
annotations: [
|
||||
{
|
||||
type: 'line',
|
||||
mode: 'vertical',
|
||||
scaleID: 'x-axis-0',
|
||||
value: 'March',
|
||||
borderColor: 'orange',
|
||||
borderWidth: 2,
|
||||
label: {
|
||||
enabled: true,
|
||||
fontColor: 'orange',
|
||||
content: 'LineAnno'
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
public lineChartColorsSector: Color[] = [
|
||||
{ // grey
|
||||
backgroundColor: 'rgba(148,159,177,0.2)',
|
||||
borderColor: 'rgba(148,159,177,1)',
|
||||
pointBackgroundColor: 'rgba(148,159,177,1)',
|
||||
pointBorderColor: '#fff',
|
||||
pointHoverBackgroundColor: '#fff',
|
||||
pointHoverBorderColor: 'rgba(148,159,177,0.8)'
|
||||
},
|
||||
{ // dark grey
|
||||
backgroundColor: 'rgba(77,83,96,0.2)',
|
||||
borderColor: 'rgba(77,83,96,1)',
|
||||
pointBackgroundColor: 'rgba(77,83,96,1)',
|
||||
pointBorderColor: '#fff',
|
||||
pointHoverBackgroundColor: '#fff',
|
||||
pointHoverBorderColor: 'rgba(77,83,96,1)'
|
||||
},
|
||||
{ // red
|
||||
backgroundColor: 'rgba(255,0,0,0.3)',
|
||||
borderColor: 'red',
|
||||
pointBackgroundColor: 'rgba(148,159,177,1)',
|
||||
pointBorderColor: '#fff',
|
||||
pointHoverBackgroundColor: '#fff',
|
||||
pointHoverBorderColor: 'rgba(148,159,177,0.8)'
|
||||
}
|
||||
];
|
||||
public lineChartLegendSector = true;
|
||||
public lineChartTypeSector = 'line';
|
||||
|
||||
weekPurchaseList = {
|
||||
first: 0,
|
||||
second: 0,
|
||||
max: 0,
|
||||
sum: 0,
|
||||
count: 0,
|
||||
};
|
||||
|
||||
showTotalCategoryList: boolean = false;
|
||||
totalCategoryLimit: number = 10;
|
||||
totalCategoryList: any[]=[];
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private api: ApiService,
|
||||
private currencyPipe: CurrencyPipe,
|
||||
) {
|
||||
if (environment.enableAnalytics) {
|
||||
this.router.events.subscribe(event => {
|
||||
if (event instanceof NavigationEnd) {
|
||||
(<any>window).ga('set', 'page', event.urlAfterRedirects);
|
||||
(<any>window).ga('send', 'pageview');
|
||||
}
|
||||
});
|
||||
}
|
||||
this.setDate();
|
||||
this.api.orgStats().subscribe(
|
||||
result => {
|
||||
this.setWeekPurchaseList(result.weeks);
|
||||
this.setWeekData(result);
|
||||
this.setChartDataCat(result.data.cat_total);
|
||||
this.setChartDataEssential(result.data.essentials);
|
||||
this.totalCategoryList = result.data.cat_list;
|
||||
if (this.totalCategoryList) {
|
||||
this.showTotalCategoryList = true;
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('Retrieval Error');
|
||||
console.log( error._body );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private setChartDataEssential (dataEs: any) {
|
||||
this.purchaseEssential = dataEs.purchase_no_essential_total;
|
||||
this.purchaseNotEssential = dataEs.purchase_no_total - this.purchaseEssential;
|
||||
this.barChartDataEssential = [
|
||||
{data: [this.purchaseEssential], label: 'Essential', stack: '1'},
|
||||
{data: [this.purchaseNotEssential], label: 'Non-Essential', stack: '1'},
|
||||
];
|
||||
this.showEssentialBarChart = true;
|
||||
console.log(this.barChartDataEssential);
|
||||
}
|
||||
|
||||
private setChartDataCat(dataCat: any) {
|
||||
this.barChartLabelsCategory = Object.keys(dataCat);
|
||||
let barChartDataCategoryInitial = Object.keys(dataCat).map(key => dataCat[key]);
|
||||
this.barChartDataCategory = [
|
||||
{data: barChartDataCategoryInitial, label: 'Series A'},
|
||||
];
|
||||
this.showCategoryBarChart = true;
|
||||
if (this.weekList1) {
|
||||
let doughnutChartDataCategoryInitial = this.weekList1.map(function(a) {return a.value;});
|
||||
this.doughnutChartDataCategory = [
|
||||
{data: doughnutChartDataCategoryInitial, label: 'Series A'},
|
||||
];
|
||||
// setTimeout is currently a workaround for ng2-charts labels
|
||||
setTimeout(() => this.doughnutChartLabelsCategory = this.weekList1.map(function(a) {return a.category;}), 0);
|
||||
this.showCategoryDoughnutChart = true;
|
||||
}
|
||||
}
|
||||
|
||||
private setChartDataSector(dataSec: any) {
|
||||
|
||||
}
|
||||
|
||||
private setDate () {
|
||||
this.myWeek1 = moment().startOf('isoWeek').format('YYYY-MM-DD');
|
||||
}
|
||||
|
||||
private setWeekData (data: any) {
|
||||
function prop<T, K extends keyof T>(obj: T, key: K) {
|
||||
return obj[key];
|
||||
}
|
||||
this.weekList1 = prop(data.data.categories, this.myWeek1);
|
||||
}
|
||||
|
||||
public setWeekPurchaseList (data: any) {
|
||||
this.weekPurchaseList = {
|
||||
first: data.first,
|
||||
second: data.second,
|
||||
max: data.max,
|
||||
sum: data.sum,
|
||||
count: data.count,
|
||||
};
|
||||
}
|
||||
|
||||
private categoryLoadMore () {
|
||||
this.disableCategoryButton = true;
|
||||
this.totalCategoryLimit = 30;
|
||||
}
|
||||
|
||||
public getBootstrapColour(index: number) {
|
||||
return this.bootstrapColours[index % this.bootstrapColours.length];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private tooltipLabelCallback(tooltipItem: any, data: any) {
|
||||
var dataset = data.datasets[tooltipItem.datasetIndex];
|
||||
var value = dataset.data[tooltipItem.index];
|
||||
return this.currencyPipe.transform(value, 'GBP', 'symbol', '1.2-2');
|
||||
}
|
||||
|
||||
// events
|
||||
public chartClicked(e: any): void {
|
||||
}
|
||||
|
||||
public chartHovered(e: any): void {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { ChartsModule } from 'ng2-charts/ng2-charts';
|
||||
import { ChartsModule } from 'ng2-charts';
|
||||
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
|
||||
import { NgxPaginationModule } from 'ngx-pagination';
|
||||
import { AgmCoreModule, GoogleMapsAPIWrapper } from '@agm/core';
|
||||
|
@ -16,19 +16,31 @@ import { AccountEditComponent } from './account-edit.component';
|
|||
import { AddDataComponent } from './add-data.component';
|
||||
import { FeedbackComponent } from './feedback.component';
|
||||
import { TransactionLogComponent } from './transaction-log.component';
|
||||
import { CategoryMonthComponent } from './category-month.component';
|
||||
import { PayrollLogComponent } from './payroll-log.component';
|
||||
import { SuppliersComponent } from './suppliers.component';
|
||||
import { MoreStuffComponent } from './more-graphs-and-tables.component';
|
||||
import { LeaderboardComponent } from './leaderboard.component';
|
||||
import { MapComponent } from './map.component';
|
||||
import { TrailMapComponent } from './trail-map.component';
|
||||
|
||||
import { GraphWidget } from '../widgets/graph-widget.component';
|
||||
import { OrgBarSnippetComponent } from '../snippets/org-snippet-bar.component';
|
||||
import { CustBarSnippetComponent } from '../snippets/cust-snippet-bar.component';
|
||||
import { GraphPanel } from '../panels/graph-panel.component';
|
||||
import { BubbleChartComponent } from '../panels/bubble-panel.component';
|
||||
import { PiePanel } from '../panels/pie-panel.component';
|
||||
import { OrgPiePanel } from '../panels/org-pie-panel.component';
|
||||
|
||||
import { DashboardRoutingModule } from './dashboard.routing';
|
||||
import { OrgResultComponent } from '../shared/org-result.component';
|
||||
import { OrgTableComponent } from '../shared/org-table.component';
|
||||
import { RecurResultComponent } from '../shared/recur-result.component';
|
||||
import { RecurTableComponent } from '../shared/recur-table.component';
|
||||
import { TransactionResultComponent } from '../shared/transaction-result.component';
|
||||
import { SupplierResultComponent } from '../shared/supplier-result.component';
|
||||
import { WardResultComponent } from '../shared/ward-result.component';
|
||||
import { MetaTypeResultComponent } from '../shared/meta-type-result.component';
|
||||
import { PayrollResultComponent } from '../shared/payroll-result.component';
|
||||
import { LeaderboardResultComponent } from '../shared/leaderboard-result.component';
|
||||
|
||||
|
@ -58,8 +70,14 @@ import { environment } from '../../environments/environment';
|
|||
AddDataComponent,
|
||||
OrgResultComponent,
|
||||
OrgTableComponent,
|
||||
RecurResultComponent,
|
||||
RecurTableComponent,
|
||||
TransactionLogComponent,
|
||||
CategoryMonthComponent,
|
||||
TransactionResultComponent,
|
||||
SupplierResultComponent,
|
||||
WardResultComponent,
|
||||
MetaTypeResultComponent,
|
||||
PayrollLogComponent,
|
||||
PayrollResultComponent,
|
||||
LeaderboardComponent,
|
||||
|
@ -69,7 +87,13 @@ import { environment } from '../../environments/environment';
|
|||
FeedbackComponent,
|
||||
GraphWidget,
|
||||
OrgBarSnippetComponent,
|
||||
CustBarSnippetComponent,
|
||||
GraphPanel,
|
||||
PiePanel,
|
||||
OrgPiePanel,
|
||||
BubbleChartComponent,
|
||||
SuppliersComponent,
|
||||
MoreStuffComponent,
|
||||
],
|
||||
providers: [
|
||||
CurrencyPipe,
|
||||
|
|
|
@ -12,10 +12,13 @@ import { AccountEditComponent } from './account-edit.component';
|
|||
import { AddDataComponent } from './add-data.component';
|
||||
import { FeedbackComponent } from './feedback.component';
|
||||
import { TransactionLogComponent } from './transaction-log.component';
|
||||
import { CategoryMonthComponent } from './category-month.component';
|
||||
import { PayrollLogComponent } from './payroll-log.component';
|
||||
import { LeaderboardComponent } from './leaderboard.component';
|
||||
import { MapComponent } from './map.component';
|
||||
import { TrailMapComponent } from './trail-map.component';
|
||||
import { MoreStuffComponent } from './more-graphs-and-tables.component';
|
||||
import { SuppliersComponent } from './suppliers.component';
|
||||
|
||||
// Using child path to allow for FullLayout theming
|
||||
const routes: Routes = [
|
||||
|
@ -58,6 +61,11 @@ const routes: Routes = [
|
|||
component: TransactionLogComponent,
|
||||
data: { title: 'Transaction Log' },
|
||||
},
|
||||
{
|
||||
path: 'category-month',
|
||||
component: CategoryMonthComponent,
|
||||
data: { title: 'Budget' },
|
||||
},
|
||||
{
|
||||
path: 'map',
|
||||
component: MapComponent,
|
||||
|
@ -66,7 +74,7 @@ const routes: Routes = [
|
|||
{
|
||||
path: 'story-trail',
|
||||
component: TrailMapComponent,
|
||||
data: { title: 'Lancaster Independent Story' },
|
||||
data: { title: 'Story Trail' },
|
||||
},
|
||||
{
|
||||
path: 'payroll-log',
|
||||
|
@ -78,6 +86,16 @@ const routes: Routes = [
|
|||
path: 'feedback',
|
||||
component: FeedbackComponent,
|
||||
data: { title: 'Give Feedback' },
|
||||
},
|
||||
{
|
||||
path: 'suppliers',
|
||||
component: SuppliersComponent,
|
||||
data: { title: 'Suppliers' }
|
||||
},
|
||||
{
|
||||
path: 'more-graphs-and-tables',
|
||||
component: MoreStuffComponent,
|
||||
data: { title: 'Infographics'}
|
||||
}
|
||||
],
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Validators, FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { ApiService } from '../providers/api-service';
|
||||
import 'rxjs/add/operator/map';
|
||||
|
||||
|
||||
@Component({
|
||||
templateUrl: 'feedback.component.html',
|
||||
|
@ -55,9 +55,7 @@ export class FeedbackComponent implements OnInit {
|
|||
result => {
|
||||
if ( result.success === true ) {
|
||||
console.log('Successful Upload');
|
||||
console.log(result);
|
||||
this.feedbackFormStatus = 'success';
|
||||
console.log(this.feedbackFormStatus);
|
||||
this.feedbackForm.patchValue({
|
||||
feedbacktext: '',
|
||||
});
|
||||
|
@ -65,22 +63,16 @@ export class FeedbackComponent implements OnInit {
|
|||
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);
|
||||
const jsonError = error.json();
|
||||
console.log('boop');
|
||||
this.feedbackFormStatusError = '"' + jsonError.error + '" Error, ' + jsonError.message;
|
||||
this.feedbackFormStatusError = '"' + error.error.error + '" Error, ' + error.error.message;
|
||||
} catch (e) {
|
||||
this.feedbackFormStatusError = 'There was a server error, please try again later.';
|
||||
}
|
||||
this.feedbackFormStatus = 'send_failed';
|
||||
console.log(this.feedbackFormStatus);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
<thead>
|
||||
<tr>
|
||||
<th>Position</th>
|
||||
<th>Value</th>
|
||||
<th>Purchase Time</th>
|
||||
<th>Name</th>
|
||||
<th class="js-sort-number">Gross amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
|
@ -5,7 +5,7 @@ import {PaginationInstance} from 'ngx-pagination';
|
|||
// import { PaginationControlsComponent } from 'ngx-pagination';
|
||||
// import { PaginationControlsDirective } from 'ngx-pagination';
|
||||
// import { TransactionResultComponent } from '../shared/transaction-result.component';
|
||||
import 'rxjs/add/operator/map';
|
||||
|
||||
|
||||
@Component({
|
||||
templateUrl: 'leaderboard.component.html',
|
||||
|
@ -22,7 +22,7 @@ export class LeaderboardComponent implements OnInit {
|
|||
|
||||
public paginateConfig: PaginationInstance = {
|
||||
id: 'leadpaginate',
|
||||
itemsPerPage: 10,
|
||||
itemsPerPage: 20,
|
||||
currentPage: 1,
|
||||
totalItems: 0
|
||||
};
|
||||
|
@ -70,7 +70,7 @@ export class LeaderboardComponent implements OnInit {
|
|||
console.log(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
}org
|
||||
|
||||
// // dynamically changes the row style based on player's position
|
||||
// // for instance, top three player and the player him/herself should
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<strong>Lancaster Independent Story</strong>
|
||||
<small>Required Data marked in <strong>bold</strong>.</small>
|
||||
<strong>Purchase Map</strong>
|
||||
<small>Click a marker to get location details.</small>
|
||||
</div>
|
||||
<div class="modal fade" bsModal #statusModal="bs-modal" [config]="{backdrop: false, animated: false}"
|
||||
tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
||||
|
|
|
@ -3,13 +3,13 @@ import { ApiService } from '../providers/api-service';
|
|||
import { AgmCoreModule } from '@agm/core';
|
||||
import { BsModalService, ModalDirective } from 'ngx-bootstrap/modal';
|
||||
import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';
|
||||
import 'rxjs/add/operator/map';
|
||||
|
||||
|
||||
@Component({
|
||||
templateUrl: 'map.component.html',
|
||||
})
|
||||
export class MapComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('statusModal') myStatusModal: ModalDirective;
|
||||
@ViewChild('statusModal', { static: true }) myStatusModal: ModalDirective;
|
||||
lat: number = 54.0466;
|
||||
lng: number = -2.8007;
|
||||
zoom: number = 12;
|
||||
|
|
136
src/app/dashboard/more-graphs-and-tables.component.html
Normal file
136
src/app/dashboard/more-graphs-and-tables.component.html
Normal file
|
@ -0,0 +1,136 @@
|
|||
<div class="animated fadeIn">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4>Filter</h4>
|
||||
</div>
|
||||
<div class="card-block">
|
||||
<form class="form-inline">
|
||||
<label class="mr-2" for="filter-from">From</label>
|
||||
<input id="filter-from" class="form-control" type="date" [(ngModel)]="filterFrom" name="from">
|
||||
<label class="mx-2" for="filter-to">To</label>
|
||||
<input class="form-control" id="filter-to" type="date" [(ngModel)]="filterTo" name="to">
|
||||
<button type="submit" class="btn btn-primary ml-2" (click)="loadData()">Filter</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<strong>Transaction Types</strong>
|
||||
</div>
|
||||
<div *ngIf="metaTypeListAvailable" class="card-block">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Ward</th>
|
||||
<th>Amount of Transactions</th>
|
||||
<th>Sum of Transactions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr meta-type-result *ngFor="let type of metaTypeList" [type]="type"></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div *ngIf="!metaTypeListAvailable" class="card-block">
|
||||
No Data available.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<strong>Ward Spending</strong>
|
||||
</div>
|
||||
<div *ngIf="wardListAvailable" class="card-block">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Ward</th>
|
||||
<th>Amount of Transactions</th>
|
||||
<th>Sum of Transactions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ward-result *ngFor="let ward of wardList" [ward]="ward"></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div *ngIf="!wardListAvailable" class="card-block">
|
||||
No Data available.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="animated fadeIn">
|
||||
<div class="card">
|
||||
<div class="card-block">
|
||||
<div class="row">
|
||||
<div class="col-sm-8">
|
||||
<h4 class="card-title mb-0">Supplier spend amount and number of purchases</h4>
|
||||
</div>
|
||||
</div>
|
||||
<small>vertical shows number of purchases, size of bubble shows the total spend amount, horizontal shows date</small>
|
||||
<div class="col-sm-12" *ngIf="!isBubbleChartLoaded">
|
||||
<div class="spinner"></div>
|
||||
</div>
|
||||
<div *ngIf="isBubbleChartLoaded">
|
||||
<canvas baseChart
|
||||
[datasets]="supplierBubbleChartData"
|
||||
[options]="supplierBubbleChartOptions"
|
||||
[labels]="supplierBubbleChartLabels"
|
||||
[legend]="showLegend"
|
||||
[chartType]="supplierBubbleChartType">
|
||||
</canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-block">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<h4 class="card-title mb-0">Spend & Number of Transactions</h4>
|
||||
<small>Date against Value and Number of Transactions</small>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<canvas baseChart
|
||||
[datasets]="yearSpendChartData"
|
||||
[options]="yearSpendChartOptions"
|
||||
[labels]="yearSpendChartLabels"
|
||||
[legend]="showLegend"
|
||||
[chartType]="yearSpendChartType">
|
||||
</canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-block">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<h4 class="card-title mb-0">Supplier Spend History</h4>
|
||||
</div>
|
||||
<div class="col-sm-6 hidden-sm-down">
|
||||
<button type="button" class="btn btn-danger" (click)="previousSupplierHistoryPage()">Previous Page</button>
|
||||
<button type="button" class="btn btn-info" (click)="nextSupplierHistoryPage()">Next Page</button>
|
||||
<span class="ml-2">Page {{ _supplierHistoryPage }} of {{ _supplierHistoryPages }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="isSupplierChartLoaded">
|
||||
<canvas baseChart #supplierChart
|
||||
[datasets]="supplierMonthChartData"
|
||||
[options]="supplierMonthChartOptions"
|
||||
[labels]="supplierMonthChartLabels"
|
||||
[legend]="showLegend"
|
||||
[chartType]="supplierMonthChartType">
|
||||
</canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
335
src/app/dashboard/more-graphs-and-tables.component.ts
Normal file
335
src/app/dashboard/more-graphs-and-tables.component.ts
Normal file
|
@ -0,0 +1,335 @@
|
|||
import {Component, OnInit, Input, Output, EventEmitter, ViewChild} from '@angular/core';
|
||||
import {ApiService} from '../providers/api-service';
|
||||
import {BaseChartDirective} from 'ng2-charts';
|
||||
import {CurrencyPipe} from '@angular/common';
|
||||
import {ChartType} from "chart.js";
|
||||
import * as moment from 'moment';
|
||||
|
||||
@Component({
|
||||
templateUrl: 'more-graphs-and-tables.component.html',
|
||||
})
|
||||
export class MoreStuffComponent implements OnInit {
|
||||
@Output() public onClick = new EventEmitter();
|
||||
@Input() public categories: any;
|
||||
|
||||
// Global Filter Setup
|
||||
filterFrom: any;
|
||||
filterTo: any;
|
||||
|
||||
isBubbleChartLoaded: boolean = false;
|
||||
isSupplierChartLoaded: boolean = false;
|
||||
wardList: any;
|
||||
wardListAvailable = false;
|
||||
metaTypeList: any;
|
||||
metaTypeListAvailable = false;
|
||||
|
||||
constructor(
|
||||
private api: ApiService,
|
||||
private currencyPipe: CurrencyPipe,
|
||||
) {
|
||||
let now = moment();
|
||||
this.filterTo = now.format('YYYY-MM-DD');
|
||||
now.subtract(1, 'months');
|
||||
this.filterFrom = now.format('YYYY-MM-DD');
|
||||
this.tableSummary();
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadData();
|
||||
}
|
||||
|
||||
public loadData() {
|
||||
this.tableSummary();
|
||||
this.loadYearSpend();
|
||||
this.loadSupplierBubble();
|
||||
this.loadSupplierHistory();
|
||||
}
|
||||
|
||||
public showLegend = true;
|
||||
|
||||
/*
|
||||
* Supplier Bubble Chart Setup
|
||||
*/
|
||||
|
||||
private formatGraphData(data: any): any[] {
|
||||
let graph_data = [];
|
||||
|
||||
data.data.map(item => {
|
||||
graph_data.push({
|
||||
t: item.date,
|
||||
r: item.value > 1000000 ? (item.value / 200000) : (item.value / 100000) + 5,
|
||||
supplier: item.seller,
|
||||
y: item.count,
|
||||
value: item.value,
|
||||
count: item.count,
|
||||
});
|
||||
});
|
||||
|
||||
return graph_data;
|
||||
}
|
||||
|
||||
private loadSupplierBubble() {
|
||||
this.api.loadMiscUrl('organisation/external/supplier_count', {
|
||||
from: this.filterFrom,
|
||||
to: this.filterTo,
|
||||
}).subscribe(
|
||||
result => {
|
||||
this.supplierBubbleChartData[0].data = this.formatGraphData(result);
|
||||
this.isBubbleChartLoaded = true;
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
public supplierBubbleChartType: ChartType = 'bubble';
|
||||
public supplierBubbleChartData: any[] = [
|
||||
{
|
||||
data: [],
|
||||
label: ["Spend"],
|
||||
borderColor: 'blue',
|
||||
hoverBorderColor: 'black',
|
||||
radius: 5,
|
||||
},
|
||||
];
|
||||
public supplierBubbleChartLabels: string[] = [];
|
||||
public supplierBubbleChartOptions: any = {
|
||||
responsive: true,
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: 'time',
|
||||
time: {
|
||||
unit: 'month'
|
||||
},
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'Date'
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'Number of purchases'
|
||||
}
|
||||
}]
|
||||
},
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
label: (tooltip, data) => {
|
||||
return this.bubbleTooltipCallback(tooltip, data);
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
private bubbleTooltipCallback(tooltipItem: any, data: any) {
|
||||
let dataset = data.datasets[tooltipItem.datasetIndex];
|
||||
let value = dataset.data[tooltipItem.index];
|
||||
return `${value.supplier}: ${this.currencyPipe.transform(value.value, 'GBP', 'symbol', '1.2-2')} over ${value.count} purchases`;
|
||||
}
|
||||
|
||||
private tableSummary() {
|
||||
this.api.loadMiscUrl('organisation/external/lcc_tables', {
|
||||
from: this.filterFrom,
|
||||
to: this.filterTo,
|
||||
}).subscribe(
|
||||
result => {
|
||||
this.wardList = result.wards;
|
||||
this.metaTypeList = Object.keys(result.types).map(key => result.types[key]);
|
||||
if (this.wardList) {
|
||||
this.wardListAvailable = true;
|
||||
}
|
||||
if (this.metaTypeList) {
|
||||
this.metaTypeListAvailable = true;
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log('Retrieval Error');
|
||||
console.log(error._body);
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private loadYearSpend() {
|
||||
this.api.loadMiscUrl('organisation/external/year_spend', {
|
||||
from: this.filterFrom,
|
||||
to: this.filterTo,
|
||||
}).subscribe(
|
||||
result => {
|
||||
let value_data = [];
|
||||
let count_data = [];
|
||||
|
||||
result.data.map(item => {
|
||||
value_data.push({
|
||||
t: item.date,
|
||||
y: item.value,
|
||||
});
|
||||
|
||||
count_data.push({
|
||||
t: item.date,
|
||||
y: item.count,
|
||||
});
|
||||
});
|
||||
|
||||
this.yearSpendChartData[0].data = value_data;
|
||||
this.yearSpendChartData[1].data = count_data;
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
public yearSpendChartData: any[] = [
|
||||
{
|
||||
data: [],
|
||||
label: ["Value £"],
|
||||
fill: false,
|
||||
borderColor: 'red',
|
||||
hoverBackgroundColor: '#ffa1b5',
|
||||
hoverBorderColor: 'red',
|
||||
yAxisID: 'y-value',
|
||||
},
|
||||
{
|
||||
data: [],
|
||||
label: ["Count"],
|
||||
fill: false,
|
||||
borderColor: 'blue',
|
||||
hoverBackgroundColor: '#52afed',
|
||||
hoverBorderColor: 'blue',
|
||||
yAxisID: 'y-count',
|
||||
},
|
||||
];
|
||||
public yearSpendChartOptions: any = {
|
||||
elements: {line: {tension: 0}},
|
||||
responsive: true,
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: 'time',
|
||||
time: {
|
||||
unit: 'month'
|
||||
},
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'Date'
|
||||
}
|
||||
}],
|
||||
yAxes: [
|
||||
{id: 'y-value', position: 'left', beginAtZero: true, type: 'linear'},
|
||||
{id: 'y-count', position: 'right', beginAtZero: true, type: 'linear'},
|
||||
]
|
||||
},
|
||||
};
|
||||
public yearSpendChartLabels: string[] = [];
|
||||
public yearSpendChartType: ChartType = 'line';
|
||||
|
||||
randomData() {
|
||||
return Math.random();
|
||||
}
|
||||
|
||||
lineChartUpdate() {
|
||||
this.loadYearSpend();
|
||||
|
||||
}
|
||||
|
||||
@ViewChild('supplierChart', {read: BaseChartDirective, static: false}) supplierChart: BaseChartDirective;
|
||||
|
||||
private loadSupplierHistory() {
|
||||
this.api.loadMiscUrl('organisation/external/supplier_history').subscribe(
|
||||
result => {
|
||||
this._supplierHistoryData = result.data;
|
||||
this._supplierHistoryPage = 1;
|
||||
this._supplierHistoryPages = Math.ceil(this._supplierHistoryData.length / this._supplierHistoryPerPage);
|
||||
this.updateSupplierHistoryData();
|
||||
|
||||
this.isSupplierChartLoaded = true;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private updateSupplierHistoryData() {
|
||||
|
||||
const lastResult = this._supplierHistoryPerPage * this._supplierHistoryPage;
|
||||
console.log(this._supplierHistoryPage);
|
||||
const firstResult = lastResult - this._supplierHistoryPerPage;
|
||||
|
||||
const pageData = this._supplierHistoryData.slice(firstResult, lastResult);
|
||||
console.log(pageData);
|
||||
|
||||
let labels = [];
|
||||
let year = [];
|
||||
let half = [];
|
||||
let quarter = [];
|
||||
pageData.map(item => {
|
||||
labels.push(item.name);
|
||||
year.push(item.year_total);
|
||||
half.push(item.half_total);
|
||||
quarter.push(item.quarter_total);
|
||||
});
|
||||
|
||||
this.supplierMonthChartData[0].data = quarter;
|
||||
this.supplierMonthChartData[1].data = half;
|
||||
this.supplierMonthChartData[2].data = year;
|
||||
this.supplierMonthChartLabels = labels;
|
||||
}
|
||||
|
||||
public nextSupplierHistoryPage() {
|
||||
if (this._supplierHistoryPage < this._supplierHistoryPages) {
|
||||
this._supplierHistoryPage++;
|
||||
}
|
||||
this.updateSupplierHistoryData();
|
||||
}
|
||||
|
||||
public previousSupplierHistoryPage() {
|
||||
if (this._supplierHistoryPage > 1) {
|
||||
this._supplierHistoryPage--;
|
||||
}
|
||||
this.updateSupplierHistoryData();
|
||||
}
|
||||
|
||||
private _supplierHistoryData: any[];
|
||||
private _supplierHistoryPerPage: number = 15;
|
||||
public _supplierHistoryPage: number = 1;
|
||||
public _supplierHistoryPages: number = 1;
|
||||
public supplierMonthChartData: any[] = [
|
||||
{
|
||||
data: [],
|
||||
label: ["3 Month"],
|
||||
fill: false,
|
||||
borderColor: 'red',
|
||||
hoverBorderColor: 'red',
|
||||
hoverBackgroundColor: 'red',
|
||||
},
|
||||
{
|
||||
data: [],
|
||||
label: ["6 Month"],
|
||||
fill: false,
|
||||
borderColor: 'blue',
|
||||
hoverBorderColor: 'blue',
|
||||
hoverBackgroundColor: 'blue',
|
||||
},
|
||||
{
|
||||
data: [],
|
||||
label: ["12 Month"],
|
||||
fill: false,
|
||||
borderColor: 'orange',
|
||||
hoverBorderColor: 'orange',
|
||||
hoverBackgroundColor: 'orange',
|
||||
},
|
||||
];
|
||||
public supplierMonthChartOptions: any = {
|
||||
//maintainAspectRatio: false,
|
||||
responsive: true,
|
||||
scales: {
|
||||
xAxes: [{
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'Spend amount £'
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'Supplier Names'
|
||||
}
|
||||
}]
|
||||
},
|
||||
};
|
||||
public supplierMonthChartLabels: string[] = [];
|
||||
public supplierMonthChartType: ChartType = 'horizontalBar';
|
||||
}
|
|
@ -6,7 +6,7 @@ import {PaginationInstance} 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: 'payroll-log.component.html',
|
||||
|
|
79
src/app/dashboard/suppliers.component.html
Normal file
79
src/app/dashboard/suppliers.component.html
Normal file
|
@ -0,0 +1,79 @@
|
|||
<div class="animated fadeIn">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4>Search Suppliers</h4>
|
||||
</div>
|
||||
<div *ngIf="supplierListAvailable" class="card-block">
|
||||
<div class="input-group">
|
||||
<input class="form-control" type="text" name="search" [(ngModel)]="searchText" autocomplete="off"
|
||||
placeholder="Search by Name or Postcode" (keydown.enter)="searchSuppliers()">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-primary" (click)="searchSuppliers()">Search</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="animated fadeIn">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4>List of Suppliers</h4>
|
||||
<div class="small">Click on Column Headers to change Sort Order</div>
|
||||
</div>
|
||||
<div *ngIf="supplierListAvailable" class="card-block">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th (click)="sortName()">Name <span class="fa-stack">
|
||||
<i *ngIf="sortBy !== 'name' || sortDir == 'asc'" class="fa fa-sort-up fa-stack-1x"></i>
|
||||
<i *ngIf="sortBy !== 'name' || sortDir == 'desc'" class="fa fa-sort-down fa-stack-1x"></i>
|
||||
</span></th>
|
||||
<th (click)="sortPostcode()">Postcode <span class="fa-stack">
|
||||
<i *ngIf="sortBy !== 'postcode' || sortDir == 'asc'" class="fa fa-sort-up fa-stack-1x"></i>
|
||||
<i *ngIf="sortBy !== 'postcode' || sortDir == 'desc'" class="fa fa-sort-down fa-stack-1x"></i>
|
||||
</span></th>
|
||||
<th (click)="sortSpend()">Spend <span class="fa-stack">
|
||||
<i *ngIf="sortBy !== 'spend' || sortDir == 'asc'" class="fa fa-sort-up fa-stack-1x"></i>
|
||||
<i *ngIf="sortBy !== 'spend' || sortDir == 'desc'" class="fa fa-sort-down fa-stack-1x"></i>
|
||||
</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr supplier-result *ngFor="let supplier of supplierList | paginate: paginateConfig"
|
||||
[supplier]="supplier"></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<pagination-template #p="paginationApi"
|
||||
[id]="paginateConfig.id"
|
||||
(pageChange)="loadSuppliers($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="!supplierListAvailable" class="card-block">
|
||||
No Suppliers available.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
74
src/app/dashboard/suppliers.component.ts
Normal file
74
src/app/dashboard/suppliers.component.ts
Normal file
|
@ -0,0 +1,74 @@
|
|||
import { Component, OnInit, AfterViewInit, Input, Output, EventEmitter, ViewChild, TemplateRef } from '@angular/core';
|
||||
import { ApiService } from '../providers/api-service';
|
||||
import { AgmCoreModule } from '@agm/core';
|
||||
import { BsModalService, ModalDirective } from 'ngx-bootstrap/modal';
|
||||
import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';
|
||||
import { PaginationInstance } from 'ngx-pagination';
|
||||
import { FilterPipeModule } from 'ngx-filter-pipe';
|
||||
@Component({
|
||||
templateUrl: 'suppliers.component.html',
|
||||
})
|
||||
export class SuppliersComponent implements OnInit, AfterViewInit {
|
||||
@Output() public onClick = new EventEmitter();
|
||||
@Input() public categories: any;
|
||||
public perPage: number = 10;
|
||||
|
||||
searchText: string;
|
||||
|
||||
supplierList: any;
|
||||
supplierListAvailable = false;
|
||||
sortBy = 'name';
|
||||
sortDir = 'asc';
|
||||
|
||||
public paginateConfig: PaginationInstance = {
|
||||
id: 'transpaginate',
|
||||
itemsPerPage: this.perPage,
|
||||
currentPage: 1,
|
||||
totalItems: 0
|
||||
};
|
||||
|
||||
constructor(
|
||||
private api: ApiService,
|
||||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadSuppliers(1);
|
||||
}
|
||||
|
||||
loadSuppliers(logPage: number) {
|
||||
this.api.externalSuppliers(logPage, this.sortBy, this.sortDir, this.perPage, this.searchText).subscribe(
|
||||
result => {
|
||||
this.supplierList = result.suppliers;
|
||||
if (this.supplierList) {
|
||||
this.supplierListAvailable = true;
|
||||
}
|
||||
this.paginateConfig.totalItems = result.page_no;
|
||||
this.paginateConfig.currentPage = logPage;
|
||||
},
|
||||
error => {
|
||||
console.log('Retrieval Error');
|
||||
console.log( error._body );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
sortName() { this.sortByColumn('name'); }
|
||||
sortPostcode() { this.sortByColumn('postcode'); }
|
||||
sortSpend() { this.sortByColumn('spend'); }
|
||||
|
||||
sortByColumn(name) {
|
||||
this.sortBy = name;
|
||||
this.sortDir = this.sortDir === 'asc' ? 'desc' : 'asc';
|
||||
this.loadSuppliers(1);
|
||||
}
|
||||
|
||||
searchSuppliers() {
|
||||
// Go back to page 1 when searching
|
||||
this.loadSuppliers(1);
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
}
|
||||
|
||||
}
|
|
@ -3,8 +3,40 @@
|
|||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<strong>Purchase Map</strong>
|
||||
<small>Required Data marked in <strong>bold</strong>.</small>
|
||||
<strong>Story Trail</strong>
|
||||
<div class="row">
|
||||
|
||||
<div class="col-12 col-sm-6 mb-3">
|
||||
<small>Select a Story Trail to see all the businesses in that story on the map.<br>
|
||||
Click an icon on the map to get more information.</small>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 order-12">
|
||||
<button type="button" class="btn btn-outline-info btn-lg float-right" (click)="openModalAssoc(templateAssoc)">Select Story Trail</button>
|
||||
</div>
|
||||
</div>
|
||||
<ng-template #templateAssoc>
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title pull-left">Select View</h4>
|
||||
<button type="button" class="close pull-right" aria-label="Close" (click)="modalRef2.hide()">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-6 text-center">
|
||||
<img src="assets/img/association/lis-logo.png" class="w-50" alt="lis logo"><br>
|
||||
<button type="button" class="btn btn-success mt-3" (click)="modalRef2.hide(); assocMap = 'lis'">Lancaster Independent Story</button>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 text-center">
|
||||
<img src="assets/img/association/esta-logo.png" class="w-50" alt="lis logo"><br>
|
||||
<button type="button" class="btn btn-success mt-3" (click)="modalRef2.hide(); assocMap = 'esta'">ESTA Association</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-danger" (click)="modalRef2.hide()">Close</button>
|
||||
</div>
|
||||
</ng-template>
|
||||
</div>
|
||||
<div class="modal fade" bsModal #statusModal="bs-modal" [config]="{backdrop: false, animated: false}"
|
||||
tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
||||
|
@ -45,7 +77,7 @@
|
|||
<agm-marker-cluster maxZoom="13" imagePath="https://raw.githubusercontent.com/googlemaps/v3-utility-library/master/markerclustererplus/images/m">
|
||||
<agm-marker
|
||||
*ngFor="let m of markers"
|
||||
[iconUrl]="'/assets/img/map-pin-lis.png'"
|
||||
[iconUrl]="'/assets/img/association/' + assocMap + '-map-pin.png'"
|
||||
[latitude]="m.latitude"
|
||||
[longitude]="m.longitude"
|
||||
[openInfoWindow]="false"
|
||||
|
@ -55,7 +87,7 @@
|
|||
</agm-map>
|
||||
<ng-template #template>
|
||||
<div class="modal-header d-flex justify-content-between">
|
||||
<img src="assets/img/lis_logo.png" class="w-15" alt="lis logo"><h4 class="modal-title">{{clickedMarker.name}}</h4>
|
||||
<img src="{{assocLogo}}" class="w-15" alt="lis logo"><h4 class="modal-title">{{clickedMarker.name}}</h4>
|
||||
<button type="button" class="close pull-right" aria-label="Close" (click)="modalRef.hide()">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
|
|
|
@ -3,18 +3,21 @@ import { ApiService } from '../providers/api-service';
|
|||
import { AgmCoreModule } from '@agm/core';
|
||||
import { BsModalService, ModalDirective } from 'ngx-bootstrap/modal';
|
||||
import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';
|
||||
import 'rxjs/add/operator/map';
|
||||
|
||||
|
||||
@Component({
|
||||
templateUrl: 'trail-map.component.html',
|
||||
})
|
||||
export class TrailMapComponent implements OnInit, AfterViewInit {
|
||||
@ViewChild('statusModal') myStatusModal: ModalDirective;
|
||||
@ViewChild('statusModal', { static: true }) myStatusModal: ModalDirective;
|
||||
lat: number = 54.0466;
|
||||
lng: number = -2.8007;
|
||||
zoom: number = 12;
|
||||
public modalRef: BsModalRef;
|
||||
public modalRef2: BsModalRef;
|
||||
clickedMarker: any;
|
||||
assocMap = 'lis';
|
||||
assocLogo: string;
|
||||
|
||||
dataReceived: string = 'loading';
|
||||
|
||||
|
@ -25,7 +28,9 @@ export class TrailMapComponent implements OnInit, AfterViewInit {
|
|||
constructor(
|
||||
private api: ApiService,
|
||||
private modalService: BsModalService,
|
||||
) {}
|
||||
) {
|
||||
this.assocLogo = 'assets/img/association/' + this.assocMap + '-logo.png';
|
||||
}
|
||||
|
||||
ngOnInit(): void { }
|
||||
|
||||
|
@ -41,9 +46,13 @@ export class TrailMapComponent implements OnInit, AfterViewInit {
|
|||
this.modalRef = this.modalService.show(template);
|
||||
}
|
||||
|
||||
openModalAssoc(templateAssoc: TemplateRef<any>) {
|
||||
this.modalRef2 = this.modalService.show(templateAssoc);
|
||||
}
|
||||
|
||||
public onMarkerClick(clickedMarker, template: TemplateRef<any>) {
|
||||
console.log(clickedMarker);
|
||||
this.clickedMarker = clickedMarker;
|
||||
this.assocLogo = 'assets/img/association/' + this.assocMap + '-logo.png';
|
||||
this.openModal(template);
|
||||
}
|
||||
|
||||
|
@ -64,8 +73,9 @@ export class TrailMapComponent implements OnInit, AfterViewInit {
|
|||
latitude: resp.getSouthWest().lat(),
|
||||
longitude: resp.getSouthWest().lng()
|
||||
},
|
||||
association: this.assocMap,
|
||||
}
|
||||
this.api.getLisData(mapData).subscribe(
|
||||
this.api.getAssocData(mapData).subscribe(
|
||||
result => {
|
||||
this.myStatusModal.hide();
|
||||
this.markers = result.locations;
|
||||
|
|
|
@ -1,22 +1,124 @@
|
|||
<div class="animated fadeIn">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<strong>Recurring Transactions</strong>
|
||||
<small>Select a Recurring Transaction below to edit it.</small>
|
||||
</div>
|
||||
<div *ngIf="!noRecurringList" class="card-block">
|
||||
<recur-table [recurList]="recurringTransactionList" [categories]="categoryList" (onClick)="recurringTransactionDetails($event, template)"></recur-table>
|
||||
<ng-template #template>
|
||||
<div class="modal-header d-flex justify-content-between">
|
||||
<h4 class="modal-title">Edit Recurring Transaction</h4>
|
||||
<button type="button" class="close pull-right" aria-label="Close" (click)="modalRef.hide()">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<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" [(ngModel)]="updatedTime">
|
||||
<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)]="clickedRecur.value">
|
||||
</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">Essential Purchase</label>
|
||||
<div class="col-md-9">
|
||||
<div class="input-group">
|
||||
<input type="checkbox" class="mr-auto" [(ngModel)]="clickedRecur.essential">
|
||||
</div>
|
||||
<span class="help-block">Tick if the purchase is deemed an essential purchase for budgeting purposes.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-md-3 form-control-label" for="text-input"><strong>Recurring Period</strong></label>
|
||||
<div class="col-md-9">
|
||||
<div class="input-group">
|
||||
<select type="text" class="form-control" [(ngModel)]="clickedRecur.recurring_period">
|
||||
<option value="daily">Daily</option>
|
||||
<option value="weekly">Weekly</option>
|
||||
<option value="fortnightly">Fortnightly</option>
|
||||
<option value="monthly">Monthly</option>
|
||||
<option value="quarterly">Quarterly</option>
|
||||
</select>
|
||||
</div>
|
||||
<span class="help-block">Please give the period of time the purchase will recur from "Time of Transaction".</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-md-3 form-control-label" for="text-input">Budget Type</label>
|
||||
<div class="col-md-9">
|
||||
<div class="input-group">
|
||||
<select type="text" class="form-control" [(ngModel)]="clickedRecur.category">
|
||||
<option value="0">Uncategorised</option>
|
||||
<option *ngFor="let category of categoryIdList" [ngValue]="category">
|
||||
{{ categoryList[category] }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<span class="help-block"><strong>Optional:</strong> Choose the Budget Type for the majority of the purchase.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="input-group">
|
||||
<span class="col-12"><strong>WARNING: Clicking "Delete" will completely remove the Recurring Transaction.</strong></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<div [ngSwitch]="transactionFormStatus">
|
||||
<div *ngSwitchCase="'success'" class="alert alert-success" role="alert">
|
||||
{{transactionFormStatusSuccess}}
|
||||
</div>
|
||||
<div *ngSwitchCase="'send_failed'" class="alert alert-danger" role="alert">
|
||||
{{transactionFormStatusError}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer d-flex justify-content-between">
|
||||
<button type="submit" (click)="deleteRecurringTransaction()" class="btn btn-sm btn-danger"><i class="fa fa-times"></i> Delete</button>
|
||||
<button type="submit" (click)="editRecurringTransaction()" class="btn btn-sm btn-primary"><i class="fa fa-dot-circle-o"></i> Save</button>
|
||||
</div>
|
||||
</ng-template>
|
||||
</div>
|
||||
<div *ngIf="noRecurringList" class="card-block">
|
||||
No Recurring Transactions.
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<strong>Log of Outgoing Transactions</strong>
|
||||
<small>This lists all purchases that have been submitted.</small>
|
||||
<button class="btn pull-right btn-sm" (click)="toggleShowMeta()">
|
||||
<span *ngIf="!showMeta">Show</span><span *ngIf="showMeta">Hide</span> Details
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="!noTransactionList" class="card-block">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Seller</th>
|
||||
<th>Value</th>
|
||||
<th *ngIf="!showMeta">Value</th>
|
||||
<th *ngIf="showMeta">Net Value</th>
|
||||
<th *ngIf="showMeta">Sales Tax Value</th>
|
||||
<th *ngIf="showMeta">Gross Value</th>
|
||||
<th>Purchase Time</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr transaction-result *ngFor="let transaction of transactionList | paginate: paginateConfig" [transaction]="transaction"></tr>
|
||||
<tr transaction-result *ngFor="let transaction of transactionList | paginate: paginateConfig" [transaction]="transaction" [showMeta]="showMeta"></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<pagination-template #p="paginationApi"
|
||||
|
|
|
@ -1,58 +1,66 @@
|
|||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { Component, OnInit, EventEmitter, TemplateRef } from '@angular/core';
|
||||
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 { BsModalService, ModalDirective } from 'ngx-bootstrap/modal';
|
||||
import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';
|
||||
import { PaginationInstance } from 'ngx-pagination';
|
||||
import * as moment from 'moment';
|
||||
import 'rxjs/add/operator/map';
|
||||
|
||||
|
||||
@Component({
|
||||
templateUrl: 'transaction-log.component.html',
|
||||
})
|
||||
export class TransactionLogComponent implements OnInit {
|
||||
|
||||
transactionList;
|
||||
transactionList: any;
|
||||
recurringTransactionList: any;
|
||||
noTransactionList = true;
|
||||
noRecurringList = true;
|
||||
myDate: any;
|
||||
minDate: any;
|
||||
public p: any;
|
||||
public modalRef: BsModalRef;
|
||||
clickedRecur: any;
|
||||
public updatedDate: string;
|
||||
public startTime: string;
|
||||
categoryIdList: any;
|
||||
categoryList: any;
|
||||
categoryNameList: string[] = [];
|
||||
transactionFormStatus: string;
|
||||
transactionFormStatusSuccess: string;
|
||||
transactionFormStatusError = 'Error received, please try again.';
|
||||
updatedTime: string;
|
||||
showMeta = false;
|
||||
|
||||
public paginateConfig: PaginationInstance = {
|
||||
id: 'transpaginate',
|
||||
itemsPerPage: 10,
|
||||
currentPage: 1,
|
||||
totalItems: 0
|
||||
};
|
||||
id: 'transpaginate',
|
||||
itemsPerPage: 10,
|
||||
currentPage: 1,
|
||||
totalItems: 0
|
||||
};
|
||||
|
||||
constructor(
|
||||
private api: ApiService,
|
||||
private modalService: BsModalService,
|
||||
) {
|
||||
this.myDate = moment().format('YYYY-MM-DD[T]HH:mm');
|
||||
this.api.categoryList().subscribe(
|
||||
result => {
|
||||
this.categoryList = result.categories;
|
||||
this.categoryIdList = Object.keys(this.categoryList);
|
||||
},
|
||||
error => {
|
||||
console.log('Retrieval Error');
|
||||
console.log( error._body );
|
||||
}
|
||||
);
|
||||
// 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
|
||||
const aprilDate = moment().month(3).date(1);
|
||||
const now = moment();
|
||||
// Checks if current time is before April 1st, if so returns true
|
||||
const 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) {
|
||||
|
@ -66,6 +74,13 @@ export class TransactionLogComponent implements OnInit {
|
|||
this.transactionList = null;
|
||||
this.noTransactionList = true;
|
||||
}
|
||||
if (result.recurring_transactions) {
|
||||
this.recurringTransactionList = result.recurring_transactions;
|
||||
this.noRecurringList = false;
|
||||
} else {
|
||||
this.recurringTransactionList = null;
|
||||
this.noRecurringList = true;
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log(error);
|
||||
|
@ -73,4 +88,82 @@ export class TransactionLogComponent implements OnInit {
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
recurringTransactionDetails(clicked, template: TemplateRef<any>) {
|
||||
this.clickedRecur = clicked;
|
||||
this.updatedTime = moment(this.clickedRecur.display_time, 'llll').format('YYYY-MM-DD[T]HH:mm');
|
||||
this.openModal(template);
|
||||
}
|
||||
|
||||
openModal(template: TemplateRef<any>) {
|
||||
this.modalRef = this.modalService.show(template);
|
||||
}
|
||||
|
||||
editRecurringTransaction() {
|
||||
let updatedTimeSubmit = moment(this.updatedTime, 'YYYY-MM-DD[T]HH:mm').local().format('YYYY-MM-DD[T]HH:mm:ss.SSSZ');
|
||||
this.clickedRecur.display_time = moment(this.updatedTime).format('llll');
|
||||
let myParams = {
|
||||
category: (this.clickedRecur.category == 0 ? undefined : this.clickedRecur.category),
|
||||
essential: this.clickedRecur.essential,
|
||||
id: this.clickedRecur.id,
|
||||
apply_time: updatedTimeSubmit,
|
||||
recurring_period: this.clickedRecur.recurring_period,
|
||||
seller: this.clickedRecur.seller,
|
||||
value: this.clickedRecur.value,
|
||||
};
|
||||
this.api
|
||||
.recurUpdate(myParams)
|
||||
.subscribe(
|
||||
result => {
|
||||
if ( result.success === true ) {
|
||||
this.transactionFormStatus = 'success';
|
||||
this.transactionFormStatusSuccess = 'Edit Succeeded.';
|
||||
} else {
|
||||
this.transactionFormStatusError = JSON.stringify(result.status) + 'Error, ' + JSON.stringify(result.message);
|
||||
this.transactionFormStatus = 'send_failed';
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log(error);
|
||||
try {
|
||||
this.transactionFormStatusError = '"' + error.error.error + '" Error, ' + error.error.message;
|
||||
} catch (e) {
|
||||
this.transactionFormStatusError = 'There was a server error, please try again later.';
|
||||
}
|
||||
this.transactionFormStatus = 'send_failed';
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
deleteRecurringTransaction() {
|
||||
let myParams = {
|
||||
id: this.clickedRecur.id,
|
||||
};
|
||||
this.api
|
||||
.recurDelete(myParams)
|
||||
.subscribe(
|
||||
result => {
|
||||
if ( result.success === true ) {
|
||||
this.transactionFormStatus = 'success';
|
||||
this.transactionFormStatusSuccess = 'Delete Succeeded.';
|
||||
} else {
|
||||
this.transactionFormStatusError = JSON.stringify(result.status) + 'Error, ' + JSON.stringify(result.message);
|
||||
this.transactionFormStatus = 'send_failed';
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log(error);
|
||||
try {
|
||||
this.transactionFormStatusError = '"' + error.error.error + '" Error, ' + error.error.message;
|
||||
} catch (e) {
|
||||
this.transactionFormStatusError = 'There was a server error, please try again later.';
|
||||
}
|
||||
this.transactionFormStatus = 'send_failed';
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
toggleShowMeta() {
|
||||
this.showMeta = !this.showMeta;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,46 +25,99 @@
|
|||
<div class="sidebar">
|
||||
<nav class="sidebar-nav">
|
||||
<ul class="nav">
|
||||
<li class="nav-item">
|
||||
<div class="row no-gutters mt-1 d-lg-none small text-center text-muted">
|
||||
<div class="col-12">Click ☰ to Close Menu</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" routerLinkActive="active" [routerLink]="['/dashboard']">
|
||||
<i class="icon-speedometer"></i> Dashboard
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col-2"><i class="icon-speedometer"></i></div>
|
||||
<div class="col-10">Dashboard</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" routerLinkActive="active" [routerLink]="['/more-graphs-and-tables']">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col-2"><i class="icon-map"></i></div>
|
||||
<div class="col-10">Infographics</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" routerLinkActive="active" [routerLink]="['/add-data']">
|
||||
<i class="icon-basket"></i> Add Transaction
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col-2"><i class="icon-basket"></i></div>
|
||||
<div class="col-10">Add Transaction</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" routerLinkActive="active" [routerLink]="['/feedback']">
|
||||
<i class="icon-envelope-letter"></i> Enter Feedback
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col-2"><i class="icon-envelope-letter"></i></div>
|
||||
<div class="col-10">Enter Feedback</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" routerLinkActive="active" [routerLink]="['/map']">
|
||||
<i class="icon-map"></i> Purchase Map
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col-2"><i class="icon-map"></i></div>
|
||||
<div class="col-10">Purchase Map</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" routerLinkActive="active" [routerLink]="['/story-trail']">
|
||||
<i class="icon-map"></i> Lancaster Independent Story
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col-2"><i class="icon-map"></i></div>
|
||||
<div class="col-10">Story Trail</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li *ngIf="accountType == 'customer'" class="nav-item">
|
||||
<a class="nav-link" routerLinkActive="active" [routerLink]="['/leaderboard']">
|
||||
<i class="icon-basket"></i> Leaderboard
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col-2"><i class="icon-basket"></i></div>
|
||||
<div class="col-10">Leaderboard</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" routerLinkActive="active" [routerLink]="['/transaction-log']">
|
||||
<i class="icon-basket"></i> Transaction Log
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col-2"><i class="icon-basket"></i></div>
|
||||
<div class="col-10">Transaction Log</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li *ngIf="accountType == 'organisation'" class="nav-item">
|
||||
<a class="nav-link" routerLinkActive="active" [routerLink]="['/payroll-log']">
|
||||
<i class="icon-basket"></i> Payroll Log
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" routerLinkActive="active" [routerLink]="['/category-month']">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col-2"><i class="icon-basket"></i></div>
|
||||
<div class="col-10">Budget</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" routerLinkActive="active" [routerLink]="['/suppliers']">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col-2"><i class="icon-speedometer"></i></div>
|
||||
<div class="col-10">Suppliers</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li *ngIf="accountType == 'organisation'" class="nav-item">
|
||||
<a class="nav-link" routerLinkActive="active" [routerLink]="['/payroll-log']">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col-2"><i class="icon-basket"></i></div>
|
||||
<div class="col-10">Payroll Log</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
@ -39,7 +39,6 @@ export class FullLayoutComponent implements OnInit {
|
|||
.logout()
|
||||
.subscribe(
|
||||
result => {
|
||||
console.log('Logged out!');
|
||||
localStorage.clear();
|
||||
this.router.navigate(['/login']);
|
||||
}
|
||||
|
|
13
src/app/panels/bubble-panel.component.html
Normal file
13
src/app/panels/bubble-panel.component.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
<div>
|
||||
<div>
|
||||
<div style="display: block">
|
||||
<canvas baseChart
|
||||
[datasets]="bubbleChartData"
|
||||
[options]="bubbleChartOptions"
|
||||
[colors]="bubbleChartColors"
|
||||
[legend]="bubbleChartLegend"
|
||||
[chartType]="bubbleChartType">
|
||||
</canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
97
src/app/panels/bubble-panel.component.ts
Normal file
97
src/app/panels/bubble-panel.component.ts
Normal file
|
@ -0,0 +1,97 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { ChartOptions, ChartType, ChartDataSets } from 'chart.js';
|
||||
import { Color } from 'ng2-charts';
|
||||
|
||||
@Component({
|
||||
selector: 'app-bubble-chart',
|
||||
templateUrl: './bubble-panel.component.html',
|
||||
})
|
||||
export class BubbleChartComponent implements OnInit {
|
||||
public bubbleChartOptions: ChartOptions = {
|
||||
responsive: true,
|
||||
scales: {
|
||||
xAxes: [
|
||||
{
|
||||
ticks: {
|
||||
min: 0,
|
||||
max: 30,
|
||||
}
|
||||
}
|
||||
],
|
||||
yAxes: [
|
||||
{
|
||||
ticks: {
|
||||
min: 0,
|
||||
max: 30,
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
public bubbleChartType: ChartType = 'bubble';
|
||||
public bubbleChartLegend = true;
|
||||
|
||||
public bubbleChartData: ChartDataSets[] = [
|
||||
{
|
||||
data: [
|
||||
{ x: 10, y: 10, r: 10 },
|
||||
{ x: 15, y: 5, r: 15 },
|
||||
{ x: 26, y: 12, r: 23 },
|
||||
{ x: 7, y: 8, r: 8 },
|
||||
],
|
||||
label: 'Series A',
|
||||
backgroundColor: 'green',
|
||||
borderColor: 'blue',
|
||||
hoverBackgroundColor: 'purple',
|
||||
hoverBorderColor: 'red',
|
||||
},
|
||||
];
|
||||
|
||||
public bubbleChartColors: Color[] = [
|
||||
{
|
||||
backgroundColor: [
|
||||
'red',
|
||||
'green',
|
||||
'blue',
|
||||
'purple',
|
||||
'yellow',
|
||||
'brown',
|
||||
'magenta',
|
||||
'cyan',
|
||||
'orange',
|
||||
'pink'
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
// events
|
||||
public chartClicked({ event, active }: { event: MouseEvent, active: {}[] }): void {
|
||||
console.log(event, active);
|
||||
}
|
||||
|
||||
public chartHovered({ event, active }: { event: MouseEvent, active: {}[] }): void {
|
||||
console.log(event, active);
|
||||
}
|
||||
|
||||
private rand(max: number) {
|
||||
return Math.trunc(Math.random() * max);
|
||||
}
|
||||
|
||||
private randomPoint(maxCoordinate: number) {
|
||||
const x = this.rand(maxCoordinate);
|
||||
const y = this.rand(maxCoordinate);
|
||||
const r = this.rand(30) + 5;
|
||||
return { x, y, r };
|
||||
}
|
||||
|
||||
public randomize(): void {
|
||||
const numberOfPoints = this.rand(5) + 5;
|
||||
const data = Array.apply(null, { length: numberOfPoints }).map(r => this.randomPoint(30));
|
||||
this.bubbleChartData[0].data = data;
|
||||
}
|
||||
}
|
|
@ -1,18 +1,9 @@
|
|||
<div class="card">
|
||||
<div class="card-block">
|
||||
<div class="row">
|
||||
<div class="col-sm-5">
|
||||
<div class="col-sm-12">
|
||||
<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"
|
||||
|
|
|
@ -82,12 +82,12 @@ export class GraphPanel implements OnInit {
|
|||
pointHoverBackgroundColor: '#fff'
|
||||
},
|
||||
{ // brandSuccess
|
||||
backgroundColor: 'transparent',
|
||||
backgroundColor: this.convertHex(this.brandInfo, 10),
|
||||
borderColor: this.brandSuccess,
|
||||
pointHoverBackgroundColor: '#fff'
|
||||
},
|
||||
{ // brandDanger
|
||||
backgroundColor: 'transparent',
|
||||
backgroundColor: this.convertHex(this.brandDanger, 10),
|
||||
borderColor: this.brandDanger,
|
||||
pointHoverBackgroundColor: '#fff',
|
||||
borderWidth: 1,
|
||||
|
|
19
src/app/panels/org-pie-panel.component.html
Normal file
19
src/app/panels/org-pie-panel.component.html
Normal file
|
@ -0,0 +1,19 @@
|
|||
<div class="card">
|
||||
<div class="card-block">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h4 class="card-title mb-0">Global Purchases by Type</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart-wrapper">
|
||||
<canvas baseChart class="chart"
|
||||
[data]="doughnutChartDataLocal"
|
||||
[labels]="doughnutChartLabelsLocal"
|
||||
[colors]="doughnutChartColors"
|
||||
[legend]="chartLegend"
|
||||
[chartType]="chartType"
|
||||
(chartHover)="chartHovered($event)"
|
||||
(chartClick)="chartClicked($event)"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
86
src/app/panels/org-pie-panel.component.ts
Normal file
86
src/app/panels/org-pie-panel.component.ts
Normal file
|
@ -0,0 +1,86 @@
|
|||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { ApiService } from '../providers/api-service';
|
||||
import { OrgPiesService } from '../providers/org-pies.service';
|
||||
import { DataType } from '../shared/data-types.enum';
|
||||
import { ChartData } from '../_interfaces/chart-data';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'org-pie-panel',
|
||||
templateUrl: 'org-pie-panel.component.html',
|
||||
})
|
||||
|
||||
export class OrgPiePanel implements OnInit {
|
||||
|
||||
public chartType = 'pie';
|
||||
public chartLegend = true;
|
||||
public doughnutChartDataLocal: number[] = [];
|
||||
public doughnutChartColors: any[] = [
|
||||
{
|
||||
backgroundColor:[
|
||||
'#ffa1b5',
|
||||
'#3cde52',
|
||||
'#52afed',
|
||||
'#c133e3',
|
||||
'#f7fa08',
|
||||
'#75152d',
|
||||
'#ee12ee',
|
||||
'#15eaea',
|
||||
'#eaa015',
|
||||
'#ea1515',
|
||||
'#2d4fcc'
|
||||
]
|
||||
},
|
||||
{
|
||||
borderColor: [
|
||||
'red',
|
||||
'green',
|
||||
'blue',
|
||||
'purple',
|
||||
'yellow',
|
||||
'brown',
|
||||
'magenta',
|
||||
'cyan',
|
||||
'orange',
|
||||
'pink'
|
||||
]
|
||||
},
|
||||
{ borderWidth: [100]
|
||||
},
|
||||
];
|
||||
|
||||
public doughnutChartLabelsLocal: string[] = [];
|
||||
|
||||
constructor(
|
||||
private api: ApiService,
|
||||
private pieService: OrgPiesService,
|
||||
) {
|
||||
this.pieService.getOrgPie().subscribe(
|
||||
result => {
|
||||
this.setChartData(result.local_all);
|
||||
},
|
||||
error => {
|
||||
console.log('Retrieval Error');
|
||||
console.log( error._body );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
|
||||
}
|
||||
|
||||
private setChartData(dataLocal: any) {
|
||||
this.doughnutChartDataLocal = Object.keys(dataLocal).map(key => dataLocal[key]);
|
||||
// setTimeout is currently a workaround for ng2-charts labels
|
||||
setTimeout(() => this.doughnutChartLabelsLocal = Object.keys(dataLocal), 0);
|
||||
}
|
||||
|
||||
// events
|
||||
public chartClicked(e: any): void {
|
||||
}
|
||||
|
||||
public chartHovered(e: any): void {
|
||||
}
|
||||
|
||||
}
|
19
src/app/panels/pie-panel.component.html
Normal file
19
src/app/panels/pie-panel.component.html
Normal file
|
@ -0,0 +1,19 @@
|
|||
<div class="card">
|
||||
<div class="card-block">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h4 class="card-title mb-0">All Purchases by Category</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart-wrapper">
|
||||
<canvas baseChart class="chart"
|
||||
[data]="doughnutChartDataLocal"
|
||||
[labels]="doughnutChartLabelsLocal"
|
||||
[colors]="doughnutChartColors"
|
||||
[legend]="chartLegend"
|
||||
[chartType]="chartType"
|
||||
(chartHover)="chartHovered($event)"
|
||||
(chartClick)="chartClicked($event)"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
94
src/app/panels/pie-panel.component.ts
Normal file
94
src/app/panels/pie-panel.component.ts
Normal file
|
@ -0,0 +1,94 @@
|
|||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { ApiService } from '../providers/api-service';
|
||||
import { CustPiesService } from '../providers/cust-pies.service';
|
||||
import { DataType } from '../shared/data-types.enum';
|
||||
import { ChartData } from '../_interfaces/chart-data';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'panel-pie',
|
||||
templateUrl: 'pie-panel.component.html',
|
||||
})
|
||||
|
||||
export class PiePanel implements OnInit {
|
||||
|
||||
public chartType = 'pie';
|
||||
public chartLegend = true;
|
||||
public doughnutChartDataLocal: number[] = [];
|
||||
public doughnutChartLabelsLocal: string[] = [];
|
||||
public doughnutChartColors: any[] = [
|
||||
{ backgroundColor: [
|
||||
'#ffa1b5',
|
||||
'#3cde52',
|
||||
'#52afed',
|
||||
'#c133e3',
|
||||
'#f7fa08',
|
||||
'#75152d',
|
||||
'#ee12ee',
|
||||
'#15eaea',
|
||||
'#eaa015',
|
||||
'#ea1515',
|
||||
'#2d4fcc'
|
||||
]
|
||||
},
|
||||
{ borderColor:[
|
||||
'red',
|
||||
'green',
|
||||
'blue',
|
||||
'purple',
|
||||
'yellow',
|
||||
'brown',
|
||||
'magenta',
|
||||
'cyan',
|
||||
'orange',
|
||||
'pink'
|
||||
]
|
||||
},
|
||||
{ borderWidth: [10]
|
||||
}
|
||||
];
|
||||
|
||||
constructor(
|
||||
private api: ApiService,
|
||||
private pieService: CustPiesService,
|
||||
) {
|
||||
this.pieService.getPie().subscribe(
|
||||
result => {
|
||||
this.setChartData(result.local_all);
|
||||
},
|
||||
error => {
|
||||
console.log('Retrieval Error');
|
||||
console.log( error._body );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
|
||||
}
|
||||
|
||||
private setChartData(dataLocal: any) {
|
||||
this.doughnutChartDataLocal = Object.keys(dataLocal).map(key => dataLocal[key]);
|
||||
// setTimeout is currently a workaround for ng2-charts labels
|
||||
setTimeout(() => this.doughnutChartLabelsLocal = Object.keys(dataLocal), 0);
|
||||
}
|
||||
|
||||
// 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 {
|
||||
}
|
||||
|
||||
public chartHovered(e: any): void {
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
import { map } from 'rxjs/operators';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/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 */
|
||||
|
||||
|
@ -29,18 +29,15 @@ export class ApiService {
|
|||
// 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');
|
||||
}
|
||||
|
@ -57,8 +54,8 @@ export class ApiService {
|
|||
.post<any>(
|
||||
this.apiUrl + '/login',
|
||||
data
|
||||
)
|
||||
.map(
|
||||
).pipe(
|
||||
map(
|
||||
result => {
|
||||
const json = result;
|
||||
this.setSessionKey(json.session_key);
|
||||
|
@ -69,24 +66,23 @@ export class ApiService {
|
|||
this.setUserType(json.user_type);
|
||||
return json;
|
||||
}
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
public logout() {
|
||||
console.log(this.sessionKey);
|
||||
const key = this.sessionKey;
|
||||
return this.http
|
||||
.post<any>(
|
||||
this.apiUrl + '/logout',
|
||||
{ session_key : key },
|
||||
)
|
||||
.map(
|
||||
).pipe(
|
||||
map(
|
||||
response => {
|
||||
localStorage.clear();
|
||||
this.sessionKey = null;
|
||||
return response;
|
||||
}
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
// Submits feedback
|
||||
|
@ -96,7 +92,6 @@ export class ApiService {
|
|||
data.package_name = 'Foodloop Web';
|
||||
data.version_code = 'dev';
|
||||
data.version_number = 'dev';
|
||||
console.log(data);
|
||||
return this.http.post<any>(
|
||||
this.apiUrl + '/feedback',
|
||||
data
|
||||
|
@ -116,6 +111,65 @@ export class ApiService {
|
|||
);
|
||||
}
|
||||
|
||||
// Basic Customer User stats API
|
||||
public categoryList() {
|
||||
const key = this.sessionKey;
|
||||
return this.http.post<any>(
|
||||
this.apiUrl + '/search/category',
|
||||
{
|
||||
session_key : key,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Basic Customer User stats API
|
||||
public categoryTransactionList() {
|
||||
const key = this.sessionKey;
|
||||
return this.http.post<any>(
|
||||
this.apiUrl + '/stats/category',
|
||||
{
|
||||
session_key : key,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// LCC data
|
||||
public externalTransactions() {
|
||||
const key = this.sessionKey;
|
||||
return this.http.post<any>(
|
||||
this.apiUrl + '/v1/organisation/external/transactions',
|
||||
{
|
||||
session_key : key,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public loadMiscUrl(extra_url, extraArgs = {}) {
|
||||
const key = this.sessionKey;
|
||||
return this.http.post<any>(
|
||||
this.apiUrl + '/v1/' + extra_url,
|
||||
{
|
||||
session_key : key,
|
||||
...extraArgs,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public externalSuppliers(page, sortBy, sortDir, perPage, search) {
|
||||
const key = this.sessionKey;
|
||||
return this.http.post<any>(
|
||||
this.apiUrl + '/v1/organisation/external/suppliers',
|
||||
{
|
||||
session_key : key,
|
||||
page : page,
|
||||
sort_by : sortBy,
|
||||
sort_dir : sortDir,
|
||||
per_page : perPage,
|
||||
search : search,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Searches organisations used for transaction submission
|
||||
|
||||
public search(data) {
|
||||
|
@ -136,6 +190,26 @@ export class ApiService {
|
|||
);
|
||||
}
|
||||
|
||||
// Edits a recurring transaction
|
||||
|
||||
public recurUpdate(data) {
|
||||
data.session_key = this.sessionKey;
|
||||
return this.http.post<any>(
|
||||
this.apiUrl + '/recurring-transactions',
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
// Edits a recurring transaction
|
||||
|
||||
public recurDelete(data) {
|
||||
data.session_key = this.sessionKey;
|
||||
return this.http.post<any>(
|
||||
this.apiUrl + '/recurring-transactions/delete',
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
// gets payroll list for log
|
||||
|
||||
public payrollList(data) {
|
||||
|
@ -188,7 +262,6 @@ export class ApiService {
|
|||
public setUserInfo(
|
||||
email: string,
|
||||
display_name: string) {
|
||||
console.log('set UserInfo');
|
||||
localStorage.setItem('email', email);
|
||||
localStorage.setItem('displayname', display_name);
|
||||
}
|
||||
|
@ -196,7 +269,6 @@ export class ApiService {
|
|||
// Sets usertype
|
||||
|
||||
public setUserType(user_type: string) {
|
||||
console.log('set UserType');
|
||||
localStorage.setItem('usertype', user_type);
|
||||
}
|
||||
|
||||
|
@ -221,33 +293,27 @@ export class ApiService {
|
|||
// 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');
|
||||
}
|
||||
|
||||
|
@ -276,20 +342,31 @@ export class ApiService {
|
|||
);
|
||||
}
|
||||
|
||||
// Load LIS Data
|
||||
public getLisData(data) {
|
||||
// Load Association Data
|
||||
public getAssocData(data) {
|
||||
data.session_key = this.sessionKey;
|
||||
return this.http.post<any>(
|
||||
this.apiUrl + '/v1/supplier/location/lis',
|
||||
this.apiUrl + '/v1/supplier/location/trail',
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
// Basic Customer User stats API
|
||||
public basicStats() {
|
||||
public customerStats() {
|
||||
const key = this.sessionKey;
|
||||
return this.http.post<any>(
|
||||
this.apiUrl + '/stats',
|
||||
this.apiUrl + '/stats/customer',
|
||||
{
|
||||
session_key : key,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Basic Customer User stats API
|
||||
public orgStats() {
|
||||
const key = this.sessionKey;
|
||||
return this.http.post<any>(
|
||||
this.apiUrl + '/stats/organisation',
|
||||
{
|
||||
session_key : key,
|
||||
}
|
||||
|
|
14
src/app/providers/cust-graphs.service.ts
Normal file
14
src/app/providers/cust-graphs.service.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { ApiService } from './api-service';
|
||||
|
||||
@Injectable()
|
||||
export class CustGraphsService {
|
||||
private custGraphUrl = '/v1/customer/graphs';
|
||||
|
||||
constructor(private api: ApiService) { }
|
||||
|
||||
public getGraph(name: string, data: any = {}) {
|
||||
data.graph = name;
|
||||
return this.api.post(this.custGraphUrl, data);
|
||||
}
|
||||
}
|
14
src/app/providers/cust-pies.service.ts
Normal file
14
src/app/providers/cust-pies.service.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { ApiService } from './api-service';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
@Injectable()
|
||||
export class CustPiesService {
|
||||
private custPieUrl = '/v1/customer/pies';
|
||||
|
||||
constructor(private api: ApiService) { }
|
||||
|
||||
public getPie(): Observable<any> {
|
||||
return this.api.post(this.custPieUrl);
|
||||
}
|
||||
}
|
15
src/app/providers/cust-snippets.service.ts
Normal file
15
src/app/providers/cust-snippets.service.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { ApiService } from './api-service';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
@Injectable()
|
||||
export class CustSnippetsService {
|
||||
private custSnippetsUrl = '/v1/customer/snippets';
|
||||
|
||||
constructor(private api: ApiService) { }
|
||||
|
||||
// This endpoint should mimic basicStats
|
||||
public getData(): Observable<any> {
|
||||
return this.api.post(this.custSnippetsUrl);
|
||||
}
|
||||
}
|
14
src/app/providers/org-pies.service.ts
Normal file
14
src/app/providers/org-pies.service.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { ApiService } from './api-service';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
@Injectable()
|
||||
export class OrgPiesService {
|
||||
private orgPieUrl = '/v1/organisation/pies';
|
||||
|
||||
constructor(private api: ApiService) { }
|
||||
|
||||
public getOrgPie(): Observable<any> {
|
||||
return this.api.post(this.orgPieUrl);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { ApiService } from './api-service';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
@Injectable()
|
||||
export class OrgSnippetsService {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
|
||||
import {filter} from 'rxjs/operators';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
|
||||
import 'rxjs/add/operator/filter';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-breadcrumbs',
|
||||
|
@ -18,7 +20,7 @@ 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.router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe(event => {
|
||||
this.breadcrumbs = [];
|
||||
let currentRoute = this.route.root,
|
||||
url = '';
|
||||
|
|
3
src/app/shared/meta-type-result.component.html
Normal file
3
src/app/shared/meta-type-result.component.html
Normal file
|
@ -0,0 +1,3 @@
|
|||
<td>{{type.type}}</td>
|
||||
<td>{{type.count}}</td>
|
||||
<td>{{type.sum | currency:'GBP':'symbol':'1.2-2' }}</td>
|
19
src/app/shared/meta-type-result.component.ts
Normal file
19
src/app/shared/meta-type-result.component.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||
|
||||
interface MetaTypeData {
|
||||
type: string;
|
||||
sum: number;
|
||||
count: number;
|
||||
}
|
||||
|
||||
@Component({
|
||||
// tslint:disable-next-line
|
||||
selector: '[meta-type-result]',
|
||||
templateUrl: 'meta-type-result.component.html',
|
||||
})
|
||||
export class MetaTypeResultComponent implements OnInit {
|
||||
@Input() public type: MetaTypeData;
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
}
|
6
src/app/shared/recur-result.component.html
Normal file
6
src/app/shared/recur-result.component.html
Normal file
|
@ -0,0 +1,6 @@
|
|||
<td (click)="recurClick()">{{recur.seller}}</td>
|
||||
<td (click)="recurClick()">{{categories[recur.category] || 'Uncategorised'}}</td>
|
||||
<td (click)="recurClick()">{{recur.essential == 1 ? 'true' : 'false'}}</td>
|
||||
<td (click)="recurClick()">{{recur.display_time}}</td>
|
||||
<td (click)="recurClick()">{{recur.recurring_period}}</td>
|
||||
<td (click)="recurClick()">{{recur.value}}</td>
|
40
src/app/shared/recur-result.component.ts
Normal file
40
src/app/shared/recur-result.component.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
||||
import * as moment from 'moment';
|
||||
|
||||
interface RecurData {
|
||||
category: number;
|
||||
essential: number;
|
||||
id: number;
|
||||
last_updated: string;
|
||||
recurring_period: string;
|
||||
seller: string;
|
||||
start_time: string;
|
||||
value: number;
|
||||
display_time: any;
|
||||
}
|
||||
|
||||
@Component({
|
||||
// tslint:disable-next-line
|
||||
selector: '[recur-result]',
|
||||
templateUrl: 'recur-result.component.html',
|
||||
})
|
||||
export class RecurResultComponent {
|
||||
@Input() public recur: RecurData;
|
||||
@Output() public onClick = new EventEmitter();
|
||||
@Input() public categories: any;
|
||||
public updatedDate: string;
|
||||
|
||||
ngOnInit(): void {
|
||||
if (this.recur.last_updated) {
|
||||
this.recur.display_time = moment(this.recur.last_updated).format('llll');
|
||||
} else {
|
||||
this.recur.display_time = moment(this.recur.start_time).format('llll');
|
||||
}
|
||||
}
|
||||
|
||||
public recurClick(): void {
|
||||
this.onClick.emit(
|
||||
this.recur
|
||||
);
|
||||
}
|
||||
}
|
17
src/app/shared/recur-table.component.html
Normal file
17
src/app/shared/recur-table.component.html
Normal file
|
@ -0,0 +1,17 @@
|
|||
<div class="form-group row">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Seller</th>
|
||||
<th>Category</th>
|
||||
<th>Essential</th>
|
||||
<th>Last Applied</th>
|
||||
<th>Recurring Period</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr recur-result *ngFor="let recur of recurList" [categories]="categories" [recur]="recur" (onClick)="recurClick($event, template)"></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
30
src/app/shared/recur-table.component.ts
Normal file
30
src/app/shared/recur-table.component.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { RecurResultComponent } from '../shared/recur-result.component';
|
||||
|
||||
interface RecurData {
|
||||
category: string;
|
||||
essential: number;
|
||||
id: number;
|
||||
last_updated: string;
|
||||
recurring_period: string;
|
||||
seller: string;
|
||||
start_time: string;
|
||||
value: number;
|
||||
display_time: any;
|
||||
}
|
||||
|
||||
@Component({
|
||||
// tslint:disable-next-line
|
||||
selector: 'recur-table',
|
||||
templateUrl: 'recur-table.component.html',
|
||||
})
|
||||
export class RecurTableComponent {
|
||||
@Input() public recurList: Array<RecurData>;
|
||||
@Output() public onClick = new EventEmitter();
|
||||
@Input() public categories: any;
|
||||
|
||||
|
||||
public recurClick(event: any): void {
|
||||
this.onClick.emit( event );
|
||||
}
|
||||
}
|
3
src/app/shared/supplier-result.component.html
Normal file
3
src/app/shared/supplier-result.component.html
Normal file
|
@ -0,0 +1,3 @@
|
|||
<td>{{supplier.name}}</td>
|
||||
<td>{{supplier.postcode}}</td>
|
||||
<td>{{supplier.spend | currency:'GBP':'symbol':'1.2-2' }}</td>
|
19
src/app/shared/supplier-result.component.ts
Normal file
19
src/app/shared/supplier-result.component.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||
|
||||
interface SupplierData {
|
||||
name: string;
|
||||
postcode: string;
|
||||
spend: number;
|
||||
}
|
||||
|
||||
@Component({
|
||||
// tslint:disable-next-line
|
||||
selector: '[supplier-result]',
|
||||
templateUrl: 'supplier-result.component.html',
|
||||
})
|
||||
export class SupplierResultComponent implements OnInit {
|
||||
@Input() public supplier: SupplierData;
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
}
|
|
@ -1,3 +1,6 @@
|
|||
<td>{{transaction.seller}}</td>
|
||||
<td>{{transaction.value | currency:'GBP':'symbol':'1.2-2' }}</td>
|
||||
<td *ngIf="!showMeta">{{transaction.value | currency:'GBP':'symbol':'1.2-2' }}</td>
|
||||
<td *ngIf="showMeta">{{transaction.net_value | currency:'GBP':'symbol':'1.2-2' }}</td>
|
||||
<td *ngIf="showMeta">{{transaction.sales_tax_value | currency:'GBP':'symbol':'1.2-2' }}</td>
|
||||
<td *ngIf="showMeta">{{transaction.gross_value | currency:'GBP':'symbol':'1.2-2' }}</td>
|
||||
<td>{{transactionDate}}</td>
|
||||
|
|
|
@ -14,6 +14,7 @@ interface TransactionData {
|
|||
})
|
||||
export class TransactionResultComponent implements OnInit {
|
||||
@Input() public transaction: TransactionData;
|
||||
@Input() public showMeta: boolean;
|
||||
public transactionDate: string;
|
||||
|
||||
ngOnInit(): void {
|
||||
|
|
3
src/app/shared/ward-result.component.html
Normal file
3
src/app/shared/ward-result.component.html
Normal file
|
@ -0,0 +1,3 @@
|
|||
<td>{{ward.ward}}</td>
|
||||
<td>{{ward.count}}</td>
|
||||
<td>{{ward.sum | currency:'GBP':'symbol':'1.2-2' }}</td>
|
19
src/app/shared/ward-result.component.ts
Normal file
19
src/app/shared/ward-result.component.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||
|
||||
interface WardData {
|
||||
ward: string;
|
||||
sum: number;
|
||||
count: number;
|
||||
}
|
||||
|
||||
@Component({
|
||||
// tslint:disable-next-line
|
||||
selector: '[ward-result]',
|
||||
templateUrl: 'ward-result.component.html',
|
||||
})
|
||||
export class WardResultComponent implements OnInit {
|
||||
@Input() public ward: WardData;
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
}
|
55
src/app/snippets/cust-snippet-bar.component.html
Normal file
55
src/app/snippets/cust-snippet-bar.component.html
Normal file
|
@ -0,0 +1,55 @@
|
|||
<div class="row">
|
||||
<div class="col-md-6 col-xl-3">
|
||||
<div class="card text-center" style="background-color: transparent; border: none">
|
||||
<div class="card-block">
|
||||
<ul style="list-style: none; padding-left: 0;">
|
||||
<li class="hidden-sm-down">
|
||||
<div><h5 class="text-dark-green">My Points</h5></div>
|
||||
<div class="number-circle mx-auto"><strong>{{ userSum / 10 | number:'1.0-0' }}</strong></div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-xl-3">
|
||||
<div class="card text-center" style="background-color: transparent; border: none">
|
||||
<div class="card-block">
|
||||
<ul style="list-style: none; padding-left: 0;">
|
||||
<li class="hidden-sm-down">
|
||||
<div><h5 class="text-dark-green">My Rank</h5></div>
|
||||
<div *ngIf="userPosition == 0" class="statuscontent">
|
||||
<div class="number-circle mx-auto"><strong>Unranked</strong></div>
|
||||
</div>
|
||||
<div *ngIf="userPosition != 0" class="statuscontent">
|
||||
<div class="number-circle mx-auto"><strong>{{ userPosition }}</strong></div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-xl-3">
|
||||
<div class="card text-center" style="background-color: transparent; border: none">
|
||||
<div class="card-block">
|
||||
<ul style="list-style: none; padding-left: 0;">
|
||||
<li class="hidden-sm-down">
|
||||
<div><h5 class="text-dark-green">My Total Spend</h5></div>
|
||||
<div class="number-circle mx-auto"><strong>{{ userSum | currency:'GBP':'symbol':'1.2-2' }}</strong></div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-xl-3">
|
||||
<div class="card text-center" style="background-color: transparent; border: none">
|
||||
<div class="card-block">
|
||||
<ul style="list-style: none; padding-left: 0;">
|
||||
<li class="hidden-sm-down">
|
||||
<div><h5 class="text-dark-green">Value to Local Economy</h5></div>
|
||||
<div class="number-circle mx-auto"><strong>{{ userSum * 2.3 | currency:'GBP':'symbol':'1.2-2' }}</strong></div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
26
src/app/snippets/cust-snippet-bar.component.ts
Normal file
26
src/app/snippets/cust-snippet-bar.component.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { CustSnippetsService } from '../providers/cust-snippets.service';
|
||||
|
||||
@Component({
|
||||
selector: 'snippet-bar-cust',
|
||||
templateUrl: 'cust-snippet-bar.component.html',
|
||||
})
|
||||
export class CustBarSnippetComponent implements OnInit {
|
||||
|
||||
public userSum = 0;
|
||||
public userPosition = 0;
|
||||
|
||||
constructor(
|
||||
private snippetsService: CustSnippetsService,
|
||||
) { }
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.snippetsService.getData()
|
||||
.subscribe(
|
||||
result => {
|
||||
this.userSum = result.snippets.user_sum;
|
||||
this.userPosition = result.snippets.user_position;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -2,7 +2,15 @@
|
|||
<div class="card-footer">
|
||||
<ul>
|
||||
<li class="hidden-sm-down">
|
||||
<div class="text-muted">Customers This Month</div>
|
||||
<div class="text-muted">Sales Total</div>
|
||||
<strong>{{ allSalesCount }}</strong>
|
||||
</li>
|
||||
<li class="hidden-sm-down">
|
||||
<div class="text-muted">Money Spent Total</div>
|
||||
<strong>{{ allPurchasesTotal | currency:'GBP':'symbol':'1.2-2'}}</strong>
|
||||
</li>
|
||||
<li class="hidden-sm-down">
|
||||
<div class="text-muted">Sales This Month</div>
|
||||
<strong>{{ thisMonthSalesCount }}</strong>
|
||||
</li>
|
||||
<li class="hidden-sm-down">
|
||||
|
@ -10,7 +18,7 @@
|
|||
<strong>{{ thisMonthPurchasesTotal | currency:'GBP':'symbol':'1.2-2'}}</strong>
|
||||
</li>
|
||||
<li class="hidden-sm-down">
|
||||
<div class="text-muted">Customers Today</div>
|
||||
<div class="text-muted">Sales Today</div>
|
||||
<strong>{{ todaySalesCount }}</strong>
|
||||
</li>
|
||||
<li class="hidden-sm-down">
|
||||
|
|
|
@ -7,6 +7,8 @@ import { OrgSnippetsService } from '../providers/org-snippets.service';
|
|||
})
|
||||
export class OrgBarSnippetComponent implements OnInit {
|
||||
|
||||
public allSalesCount = 0;
|
||||
public allSalesTotal = 0;
|
||||
public thisMonthSalesCount = 0;
|
||||
public thisMonthSalesTotal = 0;
|
||||
public thisWeekSalesCount = 0;
|
||||
|
@ -14,6 +16,8 @@ export class OrgBarSnippetComponent implements OnInit {
|
|||
public todaySalesCount = 0;
|
||||
public todaySalesTotal = 0;
|
||||
|
||||
public allPurchasesCount = 0;
|
||||
public allPurchasesTotal = 0;
|
||||
public thisMonthPurchasesCount = 0;
|
||||
public thisMonthPurchasesTotal = 0;
|
||||
public thisWeekPurchasesCount = 0;
|
||||
|
@ -29,6 +33,8 @@ export class OrgBarSnippetComponent implements OnInit {
|
|||
this.snippetsService.getData()
|
||||
.subscribe(
|
||||
result => {
|
||||
this.allSalesCount = result.snippets.all_sales_count;
|
||||
this.allSalesTotal = result.snippets.all_sales_total;
|
||||
this.thisMonthSalesCount = result.snippets.this_month_sales_count;
|
||||
this.thisMonthSalesTotal = result.snippets.this_month_sales_total;
|
||||
this.thisWeekSalesCount = result.snippets.this_week_sales_count;
|
||||
|
@ -36,6 +42,8 @@ export class OrgBarSnippetComponent implements OnInit {
|
|||
this.todaySalesCount = result.snippets.today_sales_count;
|
||||
this.todaySalesTotal = result.snippets.today_sales_total;
|
||||
|
||||
this.allPurchasesCount = result.snippets.all_purchases_count;
|
||||
this.allPurchasesTotal = result.snippets.all_purchases_total;
|
||||
this.thisMonthPurchasesCount = result.snippets.this_week_purchases_count;
|
||||
this.thisMonthPurchasesTotal = result.snippets.this_week_purchases_total;
|
||||
this.thisWeekPurchasesCount = result.snippets.this_month_purchases_count;
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<div class="chart-wrapper px-3" style="height:70px;">
|
||||
<canvas baseChart
|
||||
class="chart"
|
||||
[datasets]="lineChartData"
|
||||
[datasets]="lineGraphChartData"
|
||||
[labels]="lineChartLabels"
|
||||
[options]="lineChartOptions"
|
||||
[colors]="lineChartColours"
|
||||
|
|
|
@ -12,6 +12,7 @@ interface ChartData {
|
|||
selector: 'widget-graph',
|
||||
templateUrl: 'graph-widget.component.html',
|
||||
})
|
||||
|
||||
export class GraphWidget implements OnInit {
|
||||
@Input() public graphName: string;
|
||||
@Input() public graphTitle = 'Graph';
|
||||
|
@ -24,7 +25,7 @@ export class GraphWidget implements OnInit {
|
|||
public graphSum: Number = 0;
|
||||
public availableDataTypes = DataType;
|
||||
|
||||
public lineChartData: Array<ChartData> = [
|
||||
public lineGraphChartData: Array<ChartData> = [
|
||||
{
|
||||
data: [],
|
||||
label: 'Series A'
|
||||
|
@ -35,12 +36,21 @@ export class GraphWidget implements OnInit {
|
|||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: 'time',
|
||||
time: {
|
||||
unit: 'day',
|
||||
displayFormats: {
|
||||
day: 'MMM D',
|
||||
},
|
||||
tooltipFormat: 'MMM D',
|
||||
},
|
||||
gridLines: {
|
||||
color: 'transparent',
|
||||
zeroLineColor: 'transparent'
|
||||
},
|
||||
ticks: {
|
||||
fontSize: 2,
|
||||
source: 'data',
|
||||
fontColor: 'transparent',
|
||||
}
|
||||
|
||||
|
@ -54,7 +64,7 @@ export class GraphWidget implements OnInit {
|
|||
},
|
||||
elements: {
|
||||
line: {
|
||||
borderWidth: 1
|
||||
borderWidth: 2
|
||||
},
|
||||
point: {
|
||||
radius: 4,
|
||||
|
@ -106,10 +116,16 @@ export class GraphWidget implements OnInit {
|
|||
private setData(data: any) {
|
||||
this.setChartData(data.data);
|
||||
this.setChartLabels(data.labels);
|
||||
this.setChartBounds(data.bounds);
|
||||
}
|
||||
|
||||
private setChartBounds(data) {
|
||||
this.lineChartOptions.scales.xAxes[0].time.max = data.max;
|
||||
this.lineChartOptions.scales.xAxes[0].time.min = data.min;
|
||||
}
|
||||
|
||||
private setChartData(data: Array<number>) {
|
||||
this.lineChartData[0].data = data;
|
||||
this.lineGraphChartData[0].data = data;
|
||||
this.graphSum = data.reduce((a, b) => a + b, 0);
|
||||
// Set point size based on data
|
||||
if ( data.length < 15 ) {
|
||||
|
|
BIN
src/assets/img/association/esta-logo.png
Normal file
BIN
src/assets/img/association/esta-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
BIN
src/assets/img/association/esta-map-pin.png
Normal file
BIN
src/assets/img/association/esta-map-pin.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 260 KiB After Width: | Height: | Size: 260 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
@ -1,2 +0,0 @@
|
|||
ײֶgװ<67><D7B0>^• f^ױ<>jA<6A>Fמ£†ֳ₪י$<24>אQםhֿ0<D6BF>L•+l™<6C>Dבג)9;
|
||||
@¾&;q<>ƒט ©<C2A0>׀ iEֻײץֱװ0ו#ׂ¡<D782>ְְֵ<D6B0>׳bK<62>װס<D7B0>7<EFBFBD>U¦%¸x<C2B8>_x/6m‡=P<0C>?ףq‡›¶F™A$|װײ'Aט£½b1ױ<31>2א<32>~הג/,אd¡×זLֲ”P<05>¢>SL
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
export const environment = {
|
||||
production: false,
|
||||
apiUrl: 'https://dev.peartrade.org/api',
|
||||
apiUrl: 'https://dev.localspend.co.uk/api',
|
||||
mapApiKey: 'CHANGEME',
|
||||
enableAnalytics: false,
|
||||
analyticsKey: 'CHANGEME',
|
||||
};
|
||||
|
|
BIN
src/environments/environments.tar.enc
Normal file
BIN
src/environments/environments.tar.enc
Normal file
Binary file not shown.
|
@ -18,7 +18,6 @@
|
|||
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
|
||||
<body class="app header-fixed sidebar-fixed">
|
||||
<!-- Enable bootstrap 4 theme -->
|
||||
<script>window.__theme = 'bs4';</script>
|
||||
|
@ -123,6 +122,12 @@
|
|||
<div class="sk-cube3 sk-cube"></div>
|
||||
</div>
|
||||
</app-root>
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -11,11 +11,11 @@
|
|||
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
|
||||
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
|
||||
*
|
||||
* Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
|
||||
* Learn more in https://angular.io/guide/browser-support
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* BROWSER POLYFILLS
|
||||
* BROWSER POLYFILLS
|
||||
*/
|
||||
|
||||
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
|
||||
|
@ -31,23 +31,37 @@ import 'core-js/es6/date';
|
|||
import 'core-js/es6/array';
|
||||
import 'core-js/es6/regexp';
|
||||
import 'core-js/es6/map';
|
||||
import 'core-js/es6/weak-map';
|
||||
import 'core-js/es6/set';
|
||||
import 'core-js/es6/reflect';
|
||||
import 'core-js/es7/array';
|
||||
import 'core-js/es7/object';
|
||||
|
||||
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
||||
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||
|
||||
/** IE10 and IE11 requires the following to support `@angular/animation`. */
|
||||
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||
|
||||
|
||||
/** Evergreen browsers require these. **/
|
||||
/** IE10 and IE11 requires the following for the Reflect API. */
|
||||
import 'core-js/es6/reflect';
|
||||
import 'core-js/es7/reflect';
|
||||
|
||||
/**
|
||||
* Required to support Web Animations `@angular/platform-browser/animations`.
|
||||
* Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
|
||||
**/
|
||||
import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||
|
||||
/** ALL Firefox browsers require the following to support `@angular/animation`. **/
|
||||
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||
/**
|
||||
* By default, zone.js will patch all possible macroTask and DomEvents
|
||||
* user can disable parts of macroTask/DomEvents patch by setting following flags
|
||||
*/
|
||||
|
||||
(window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
|
||||
(window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
|
||||
(window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
|
||||
|
||||
/*
|
||||
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
|
||||
* with the following flag, it will bypass `zone.js` patch for IE/Edge
|
||||
*/
|
||||
(window as any).__Zone_enable_cross_context_check = true;
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -24,6 +24,25 @@ agm-map {
|
|||
width: 15%;
|
||||
}
|
||||
|
||||
// circle for text
|
||||
// TODO: Make these resize based on inside content
|
||||
.number-circle {
|
||||
height: 10rem;
|
||||
border-radius:50%;
|
||||
text-align:center;
|
||||
width: 10rem;
|
||||
padding: 5rem 5%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
background: #4dbd74;
|
||||
color: white;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.text-dark-green {
|
||||
color: #10602c;
|
||||
}
|
||||
|
||||
// white title font variant on type-2 as defined in _widgets.css
|
||||
.horizontal-bars {
|
||||
padding: 0;
|
||||
|
@ -54,7 +73,8 @@ agm-map {
|
|||
margin-bottom: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.small {
|
||||
}
|
||||
&.legend {
|
||||
text-align: center;
|
||||
|
||||
|
|
28
src/scss/bootstrap/_spinner.scss
Normal file
28
src/scss/bootstrap/_spinner.scss
Normal file
|
@ -0,0 +1,28 @@
|
|||
.spinner {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background-color: #333;
|
||||
|
||||
margin: 100px auto;
|
||||
-webkit-animation: sk-rotateplane 1.2s infinite ease-in-out;
|
||||
animation: sk-rotateplane 1.2s infinite ease-in-out;
|
||||
}
|
||||
|
||||
@-webkit-keyframes sk-rotateplane {
|
||||
0% { -webkit-transform: perspective(120px) }
|
||||
50% { -webkit-transform: perspective(120px) rotateY(180deg) }
|
||||
100% { -webkit-transform: perspective(120px) rotateY(180deg) rotateX(180deg) }
|
||||
}
|
||||
|
||||
@keyframes sk-rotateplane {
|
||||
0% {
|
||||
transform: perspective(120px) rotateX(0deg) rotateY(0deg);
|
||||
-webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg)
|
||||
} 50% {
|
||||
transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
|
||||
-webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg)
|
||||
} 100% {
|
||||
transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
|
||||
-webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
|
||||
}
|
||||
}
|
|
@ -76,3 +76,4 @@
|
|||
|
||||
// Custom styles
|
||||
@import "custom";
|
||||
@import "bootstrap/spinner";
|
|
@ -2,7 +2,6 @@
|
|||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/app",
|
||||
"module": "es2015",
|
||||
"baseUrl": "",
|
||||
"types": []
|
||||
},
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/spec",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"baseUrl": "",
|
||||
"types": [
|
||||
"jasmine",
|
||||
|
@ -11,7 +9,8 @@
|
|||
]
|
||||
},
|
||||
"files": [
|
||||
"test.ts"
|
||||
"test.ts",
|
||||
"polyfills.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"downlevelIteration": true,
|
||||
"importHelpers": true,
|
||||
"module": "esnext",
|
||||
"outDir": "./dist/out-tsc",
|
||||
"baseUrl": "src",
|
||||
"sourceMap": true,
|
||||
|
@ -8,7 +11,7 @@
|
|||
"moduleResolution": "node",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "es5",
|
||||
"target": "es2015",
|
||||
"typeRoots": [
|
||||
"node_modules/@types"
|
||||
],
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue