Merge branch 'Release-v0.1.13'
This commit is contained in:
commit
9ef666f962
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
|
*.PDF diff=astextplain
|
||||||
*.rtf diff=astextplain
|
*.rtf 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
|
/bower_components
|
||||||
|
|
||||||
# IDEs and editors
|
# IDEs and editors
|
||||||
/.idea
|
|
||||||
.project
|
.project
|
||||||
.classpath
|
.classpath
|
||||||
*.launch
|
*.launch
|
||||||
|
@ -41,11 +40,15 @@ testem.log
|
||||||
/e2e/*.js
|
/e2e/*.js
|
||||||
/e2e/*.map
|
/e2e/*.map
|
||||||
|
|
||||||
|
# build
|
||||||
|
/dist
|
||||||
|
|
||||||
# local env variable
|
# local env variable
|
||||||
/src/environments/environment.local.ts
|
/src/environments/environment.local.ts
|
||||||
/src/environments/environment.prod.ts
|
/src/environments/environment.prod.ts
|
||||||
/src/environments/environment.dev.ts
|
/src/environments/environment.dev.ts
|
||||||
/src/environments/environment.ci.ts
|
/src/environments/environment.ci.ts
|
||||||
|
/src/environments/environments.tar
|
||||||
|
|
||||||
# =========================
|
# =========================
|
||||||
# Operating System Files
|
# Operating System Files
|
||||||
|
|
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
# Default ignored files
|
||||||
|
/workspace.xml
|
6
.idea/misc.xml
generated
Normal file
6
.idea/misc.xml
generated
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
generated
Normal file
8
.idea/modules.xml
generated
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
generated
Normal file
6
.idea/vcs.xml
generated
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>
|
18
.travis.yml
18
.travis.yml
|
@ -2,14 +2,24 @@ addons:
|
||||||
chrome: stable
|
chrome: stable
|
||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- 8
|
- node
|
||||||
before_install:
|
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:
|
before_script:
|
||||||
- export DISPLAY=:99.0
|
|
||||||
- sh -e /etc/init.d/xvfb start
|
|
||||||
- npm config set spin false
|
- npm config set spin false
|
||||||
install:
|
install:
|
||||||
- npm install
|
- npm install
|
||||||
script:
|
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
|
# 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
|
# v0.0.5
|
||||||
|
|
||||||
* Change page name from Story Trail to Lancaster Independent Story
|
* 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
|
#! /bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
VERSION=`git describe --tags`
|
VERSION=`git describe --tags`
|
||||||
|
|
||||||
|
@ -11,13 +12,13 @@ echo "Building releases for $VERSION"
|
||||||
|
|
||||||
echo "Building Prod Release..."
|
echo "Building Prod Release..."
|
||||||
|
|
||||||
ng build --prod
|
npm run build:prod
|
||||||
|
|
||||||
tar -czf ../WebApp-Releases/LocalLoop-Web-prod-$VERSION.tar.gz dist
|
tar -czf ../WebApp-Releases/LocalLoop-Web-prod-$VERSION.tar.gz dist
|
||||||
|
|
||||||
echo "Building Dev Release..."
|
echo "Building Dev Release..."
|
||||||
|
|
||||||
ng build --dev
|
npm run build:dev
|
||||||
|
|
||||||
tar -czf ../WebApp-Releases/LocalLoop-Web-dev-$VERSION.tar.gz dist
|
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) {
|
module.exports = function (config) {
|
||||||
config.set({
|
config.set({
|
||||||
basePath: '',
|
basePath: '',
|
||||||
frameworks: ['jasmine', '@angular/cli'],
|
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||||
plugins: [
|
plugins: [
|
||||||
require('karma-jasmine'),
|
require('karma-jasmine'),
|
||||||
require('karma-chrome-launcher'),
|
require('karma-chrome-launcher'),
|
||||||
require('karma-jasmine-html-reporter'),
|
require('karma-jasmine-html-reporter'),
|
||||||
require('karma-coverage-istanbul-reporter'),
|
require('karma-coverage-istanbul-reporter'),
|
||||||
require('@angular/cli/plugins/karma')
|
require('@angular-devkit/build-angular/plugins/karma')
|
||||||
],
|
],
|
||||||
client:{
|
client:{
|
||||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||||
},
|
},
|
||||||
files: [
|
files: [
|
||||||
{ pattern: './src/test.ts', watched: false }
|
|
||||||
],
|
],
|
||||||
preprocessors: {
|
preprocessors: {
|
||||||
'./src/test.ts': ['@angular/cli']
|
|
||||||
},
|
},
|
||||||
mime: {
|
mime: {
|
||||||
'text/x-typescript': ['ts','tsx']
|
'text/x-typescript': ['ts','tsx']
|
||||||
},
|
},
|
||||||
coverageIstanbulReporter: {
|
coverageIstanbulReporter: {
|
||||||
reports: [ 'html', 'lcovonly' ],
|
dir: require('path').join(__dirname, 'coverage'), reports: [ 'html', 'lcovonly' ],
|
||||||
fixWebpackSourcePaths: true
|
fixWebpackSourcePaths: true
|
||||||
},
|
},
|
||||||
angularCli: {
|
angularCli: {
|
||||||
|
|
15109
package-lock.json
generated
15109
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",
|
"name": "localloop-web",
|
||||||
"version": "0.0.5",
|
"version": "0.1.13",
|
||||||
"description": "LocalLoop Web - Web interface for LocalLoop app",
|
"description": "LocalLoop Web - Web interface for LocalLoop app",
|
||||||
"author": "",
|
"author": "",
|
||||||
"url": "http://www.peartrade.org",
|
"url": "http://www.peartrade.org",
|
||||||
|
@ -8,59 +8,80 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
"start": "ng serve",
|
"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": "ng test",
|
||||||
"test:ci": "ng test --watch=false --env=ci",
|
"test:ci": "ng test --watch=false --browsers=ChromeHeadless",
|
||||||
"lint": "ng lint",
|
"lint": "ng lint",
|
||||||
"e2e": "ng e2e",
|
"e2e": "ng e2e",
|
||||||
"e2e:ci": "ng e2e --env=ci",
|
"e2e:ci": "ng e2e --configuration=ci",
|
||||||
"ci": "npm run test:ci && npm run e2e:ci"
|
"ci": "npm run test:ci && npm run e2e:ci"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@agm/core": "1.0.0-beta.2",
|
"@agm/core": "1.0.0-beta.6",
|
||||||
"@agm/js-marker-clusterer": "1.0.0-beta.2",
|
"@agm/js-marker-clusterer": "1.0.0-beta.6",
|
||||||
"@angular/common": "5.0.1",
|
"@angular/common": "8.1.0",
|
||||||
"@angular/compiler": "5.0.1",
|
"@angular/compiler": "8.1.0",
|
||||||
"@angular/core": "5.0.1",
|
"@angular/core": "8.1.0",
|
||||||
"@angular/forms": "5.0.1",
|
"@angular/forms": "8.1.0",
|
||||||
"@angular/platform-browser": "5.0.1",
|
"@angular/platform-browser": "8.1.0",
|
||||||
"@angular/platform-browser-dynamic": "5.0.1",
|
"@angular/platform-browser-dynamic": "8.1.0",
|
||||||
"@angular/router": "5.0.1",
|
"@angular/router": "8.1.0",
|
||||||
"@angular/upgrade": "5.0.1",
|
"@angular/upgrade": "8.1.0",
|
||||||
"@types/moment": "2.13.0",
|
"@coreui/coreui-plugin-chartjs-custom-tooltips": "^1.3.1",
|
||||||
"chart.js": "2.7.1",
|
"@coreui/icons": "0.3.0",
|
||||||
"core-js": "2.5.1",
|
"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",
|
"js-marker-clusterer": "1.0.0",
|
||||||
"moment": "^2.19.2",
|
"jszip": "^3.2.2",
|
||||||
"ng2-charts": "1.6.0",
|
"luxon": "^1.16.1",
|
||||||
|
"moment": "^2.24.0",
|
||||||
|
"ng2-charts": "^2.3.0",
|
||||||
"ng2-validation-manager": "0.5.3",
|
"ng2-validation-manager": "0.5.3",
|
||||||
"ngx-bootstrap": "2.0.0-beta.8",
|
"ngx-bootstrap": "^5.0.0",
|
||||||
"ngx-pagination": "3.0.3",
|
"ngx-filter-pipe": "^2.1.2",
|
||||||
"rxjs": "5.5.2",
|
"ngx-pagination": "^4.0.0",
|
||||||
|
"popper.js": "^1.15.0",
|
||||||
|
"rxjs": "6.5.2",
|
||||||
|
"stream": "0.0.2",
|
||||||
"ts-helpers": "1.1.2",
|
"ts-helpers": "1.1.2",
|
||||||
"webpack": "3.8.1",
|
"tslib": "^1.10.0",
|
||||||
"webpack-dev-server": "2.9.4",
|
"web-animations-js": "^2.3.2",
|
||||||
"zone.js": "0.8.18"
|
"webpack-dev-server": "^3.7.2",
|
||||||
|
"zone.js": "~0.9.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular/cli": "1.5.0",
|
"@angular-devkit/build-angular": "~0.801.0",
|
||||||
"@angular/compiler-cli": "5.0.1",
|
"@angular/cli": "^8.1.0",
|
||||||
"@types/jasmine": "2.8.2",
|
"@angular/compiler-cli": "8.1.0",
|
||||||
"@types/jasminewd2": "2.0.3",
|
"@types/jasmine": "3.3.13",
|
||||||
"@types/node": "8.0.52",
|
"@types/jasminewd2": "2.0.6",
|
||||||
"codelyzer": "4.0.1",
|
"@types/node": "12.0.10",
|
||||||
"jasmine-core": "2.8.0",
|
"codelyzer": "^5.1.0",
|
||||||
|
"jasmine-core": "^3.4.0",
|
||||||
"jasmine-spec-reporter": "4.2.1",
|
"jasmine-spec-reporter": "4.2.1",
|
||||||
"karma": "1.7.1",
|
"karma": "^4.1.0",
|
||||||
"karma-chrome-launcher": "2.2.0",
|
"karma-chrome-launcher": "2.2.0",
|
||||||
"karma-cli": "1.0.1",
|
"karma-cli": "2.0.0",
|
||||||
"karma-coverage-istanbul-reporter": "1.3.0",
|
"karma-coverage-istanbul-reporter": "^2.0.5",
|
||||||
"karma-jasmine": "1.1.0",
|
"karma-jasmine": "^2.0.1",
|
||||||
"karma-jasmine-html-reporter": "0.2.2",
|
"readable-stream": "latest",
|
||||||
"protractor": "5.2.0",
|
"karma-jasmine-html-reporter": "^1.4.2",
|
||||||
"ts-node": "3.3.0",
|
"protractor": "^5.4.2",
|
||||||
"tslint": "5.8.0",
|
"ts-node": "^8.3.0",
|
||||||
"typescript": "2.4.2"
|
"tslint": "^5.18.0",
|
||||||
|
"typescript": "~3.4.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,10 @@ exports.config = {
|
||||||
'./e2e/**/*.e2e-spec.ts'
|
'./e2e/**/*.e2e-spec.ts'
|
||||||
],
|
],
|
||||||
capabilities: {
|
capabilities: {
|
||||||
'browserName': 'chrome'
|
'browserName': 'chrome',
|
||||||
|
chromeOptions: {
|
||||||
|
args: [ "--headless" ]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
directConnect: true,
|
directConnect: true,
|
||||||
baseUrl: 'http://localhost:4200/',
|
baseUrl: 'http://localhost:4200/',
|
||||||
|
|
|
@ -8,13 +8,11 @@ export class AuthGuard implements CanActivate {
|
||||||
|
|
||||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||||
if (localStorage.getItem('sessionKey')) {
|
if (localStorage.getItem('sessionKey')) {
|
||||||
console.log('session key found');
|
|
||||||
// logged in so return true
|
// logged in so return true
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// not logged in so redirect to login page with the return url
|
// 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 }});
|
this.router.navigate(['/login'], { queryParams: { returnUrl: state.url }});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,9 @@ export class CustomerGuard implements CanActivate {
|
||||||
|
|
||||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||||
if (localStorage.getItem('usertype') === 'customer') {
|
if (localStorage.getItem('usertype') === 'customer') {
|
||||||
console.log('Customer logged in');
|
|
||||||
// customer logged in so return true
|
// customer logged in so return true
|
||||||
return true;
|
return true;
|
||||||
} else if (localStorage.getItem('usertype') === 'organisation') {
|
} else if (localStorage.getItem('usertype') === 'organisation') {
|
||||||
console.log('not an customer');
|
|
||||||
this.router.navigate(['/dashboard']);
|
this.router.navigate(['/dashboard']);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,9 @@ export class OrgGuard implements CanActivate {
|
||||||
|
|
||||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||||
if (localStorage.getItem('usertype') === 'organisation') {
|
if (localStorage.getItem('usertype') === 'organisation') {
|
||||||
console.log('Organisation logged in');
|
|
||||||
// org logged in so return true
|
// org logged in so return true
|
||||||
return true;
|
return true;
|
||||||
} else if (localStorage.getItem('usertype') === 'customer') {
|
} else if (localStorage.getItem('usertype') === 'customer') {
|
||||||
console.log('not an organisation');
|
|
||||||
this.router.navigate(['/dashboard-customer']);
|
this.router.navigate(['/dashboard-customer']);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
|
import { environment } from '../environments/environment';
|
||||||
|
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { LocationStrategy, HashLocationStrategy } from '@angular/common';
|
import { LocationStrategy, HashLocationStrategy } from '@angular/common';
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
|
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
|
||||||
|
@ -21,7 +24,11 @@ import { CustomerGuard } from './_guards/customer.guard';
|
||||||
import { ApiService } from './providers/api-service';
|
import { ApiService } from './providers/api-service';
|
||||||
|
|
||||||
import { OrgGraphsService } from './providers/org-graphs.service';
|
import { OrgGraphsService } from './providers/org-graphs.service';
|
||||||
|
import { CustGraphsService } from './providers/cust-graphs.service';
|
||||||
import { OrgSnippetsService } from './providers/org-snippets.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
|
// Layouts
|
||||||
import { FullLayoutComponent } from './layouts/full-layout.component';
|
import { FullLayoutComponent } from './layouts/full-layout.component';
|
||||||
|
@ -34,21 +41,30 @@ import { P500Component } from './pages/500.component';
|
||||||
// Submodules
|
// Submodules
|
||||||
import { AuthModule } from './auth/auth.module';
|
import { AuthModule } from './auth/auth.module';
|
||||||
import { DashboardModule } from './dashboard/dashboard.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({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
|
FormsModule,
|
||||||
|
FilterPipeModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
NgxPaginationModule,
|
NgxPaginationModule,
|
||||||
BsDropdownModule.forRoot(),
|
BsDropdownModule.forRoot(),
|
||||||
TabsModule.forRoot(),
|
TabsModule.forRoot(),
|
||||||
AuthModule,
|
AuthModule,
|
||||||
|
ChartsModule,
|
||||||
DashboardModule,
|
DashboardModule,
|
||||||
// Loaded last to allow for 404 catchall
|
// Loaded last to allow for 404 catchall
|
||||||
AppRoutingModule,
|
AppRoutingModule,
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
|
// StackedBarChartComponent,
|
||||||
FullLayoutComponent,
|
FullLayoutComponent,
|
||||||
SimpleLayoutComponent,
|
SimpleLayoutComponent,
|
||||||
NAV_DROPDOWN_DIRECTIVES,
|
NAV_DROPDOWN_DIRECTIVES,
|
||||||
|
@ -65,6 +81,10 @@ import { DashboardModule } from './dashboard/dashboard.module';
|
||||||
ApiService,
|
ApiService,
|
||||||
OrgGraphsService,
|
OrgGraphsService,
|
||||||
OrgSnippetsService,
|
OrgSnippetsService,
|
||||||
|
CustGraphsService,
|
||||||
|
CustSnippetsService,
|
||||||
|
CustPiesService,
|
||||||
|
OrgPiesService,
|
||||||
{
|
{
|
||||||
provide: LocationStrategy,
|
provide: LocationStrategy,
|
||||||
useClass: HashLocationStrategy
|
useClass: HashLocationStrategy
|
||||||
|
@ -72,4 +92,10 @@ import { DashboardModule } from './dashboard/dashboard.module';
|
||||||
],
|
],
|
||||||
bootstrap: [ AppComponent ]
|
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 { Validators, FormBuilder, FormGroup } from '@angular/forms';
|
||||||
import { ApiService } from '../providers/api-service';
|
import { ApiService } from '../providers/api-service';
|
||||||
import { Router, ActivatedRoute } from '@angular/router';
|
import { Router, ActivatedRoute } from '@angular/router';
|
||||||
import 'rxjs/add/operator/map';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: 'login.component.html',
|
templateUrl: 'login.component.html',
|
||||||
|
@ -40,15 +40,11 @@ export class LoginComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
onSubmit() {
|
onSubmit() {
|
||||||
console.log(this.signin.value);
|
|
||||||
|
|
||||||
this.api
|
this.api
|
||||||
.login(this.signin.value)
|
.login(this.signin.value)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
result => {
|
result => {
|
||||||
console.log('logged in!');
|
|
||||||
this.loginStatus = 'success';
|
this.loginStatus = 'success';
|
||||||
console.log(this.loginStatus);
|
|
||||||
this.router.navigate([this.returnUrl]);
|
this.router.navigate([this.returnUrl]);
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
|
|
|
@ -106,6 +106,7 @@
|
||||||
<option value='R'>Arts, Entertainment & Recreation</option>
|
<option value='R'>Arts, Entertainment & Recreation</option>
|
||||||
<option value='S'>Other Service Activities</option>
|
<option value='S'>Other Service Activities</option>
|
||||||
<option value='T'>Household Domestic Business</option>
|
<option value='T'>Household Domestic Business</option>
|
||||||
|
<option value='U'>Extraterritorial Organisations and Bodies</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { Validators, FormBuilder, FormGroup } from '@angular/forms';
|
||||||
import { ValidationManager } from 'ng2-validation-manager';
|
import { ValidationManager } from 'ng2-validation-manager';
|
||||||
import { ApiService } from '../providers/api-service';
|
import { ApiService } from '../providers/api-service';
|
||||||
import {Router } from '@angular/router';
|
import {Router } from '@angular/router';
|
||||||
import 'rxjs/add/operator/map';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: 'register.component.html',
|
templateUrl: 'register.component.html',
|
||||||
|
@ -78,24 +78,18 @@ export class RegisterComponent {
|
||||||
.register(data)
|
.register(data)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
result => {
|
result => {
|
||||||
console.log('registered!');
|
|
||||||
this.registerStatus = 'success';
|
this.registerStatus = 'success';
|
||||||
console.log(this.registerStatus);
|
|
||||||
this.router.navigate(['/dashboard']);
|
this.router.navigate(['/dashboard']);
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
console.log('Register Error');
|
console.log('Register Error');
|
||||||
console.log(error);
|
console.log(error);
|
||||||
try {
|
try {
|
||||||
console.log(error.error);
|
this.registerStatusError = '"' + error.error.error + '" Error, ' + error.error.message;
|
||||||
const jsonError = error.json();
|
|
||||||
console.log('boop');
|
|
||||||
this.registerStatusError = '"' + jsonError.error + '" Error, ' + jsonError.message;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.registerStatusError = 'There was a server error, please try again later.';
|
this.registerStatusError = 'There was a server error, please try again later.';
|
||||||
}
|
}
|
||||||
this.registerStatus = 'send_failed';
|
this.registerStatus = 'send_failed';
|
||||||
console.log(this.registerStatus);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -122,24 +116,17 @@ export class RegisterComponent {
|
||||||
town: organisationForm.town,
|
town: organisationForm.town,
|
||||||
postcode: organisationForm.postcode,
|
postcode: organisationForm.postcode,
|
||||||
};
|
};
|
||||||
console.log(data);
|
|
||||||
this.api
|
this.api
|
||||||
.register(data)
|
.register(data)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
result => {
|
result => {
|
||||||
console.log('registered!');
|
|
||||||
this.registerStatus = 'success';
|
this.registerStatus = 'success';
|
||||||
console.log(this.registerStatus);
|
|
||||||
this.router.navigate(['/dashboard']);
|
this.router.navigate(['/dashboard']);
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
console.log('Register Error');
|
|
||||||
console.log(error);
|
console.log(error);
|
||||||
try {
|
try {
|
||||||
console.log(error.error);
|
this.registerStatusError = '"' + error.error.error + '" Error, ' + error.error.message;
|
||||||
const jsonError = error.json();
|
|
||||||
console.log('boop');
|
|
||||||
this.registerStatusError = '"' + jsonError.error + '" Error, ' + jsonError.message;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.registerStatusError = 'There was a server error, please try again later.';
|
this.registerStatusError = 'There was a server error, please try again later.';
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,6 +99,7 @@
|
||||||
<option value='R'>Arts, Entertainment & Recreation</option>
|
<option value='R'>Arts, Entertainment & Recreation</option>
|
||||||
<option value='S'>Other Service Activities</option>
|
<option value='S'>Other Service Activities</option>
|
||||||
<option value='T'>Household Domestic Business</option>
|
<option value='T'>Household Domestic Business</option>
|
||||||
|
<option value='U'>Extraterritorial Organisations and Bodies</option>
|
||||||
</select>
|
</select>
|
||||||
<span class="help-block">Alter this if your business sector has changed.</span>
|
<span class="help-block">Alter this if your business sector has changed.</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
import { Validators, FormBuilder, FormGroup } from '@angular/forms';
|
import { Validators, FormBuilder, FormGroup } from '@angular/forms';
|
||||||
import { ApiService } from '../providers/api-service';
|
import { ApiService } from '../providers/api-service';
|
||||||
import 'rxjs/add/operator/map';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: 'account-edit.component.html',
|
templateUrl: 'account-edit.component.html',
|
||||||
|
@ -105,23 +105,17 @@ export class AccountEditComponent implements OnInit {
|
||||||
.accountEditUpdate(submitData)
|
.accountEditUpdate(submitData)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
result => {
|
result => {
|
||||||
console.log('data submitted!');
|
|
||||||
this.submitStatus = 'success';
|
this.submitStatus = 'success';
|
||||||
console.log(this.submitStatus);
|
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
console.log('Edit Error');
|
console.log('Edit Error');
|
||||||
console.log(error);
|
console.log(error);
|
||||||
try {
|
try {
|
||||||
console.log(error.error);
|
this.submitStatusError = '"' + error.error.error + '" Error, ' + error.error.message;
|
||||||
const jsonError = error.json();
|
|
||||||
console.log('boop');
|
|
||||||
this.submitStatusError = '"' + jsonError.error + '" Error, ' + jsonError.message;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.submitStatusError = 'There was a server error, please try again later.';
|
this.submitStatusError = 'There was a server error, please try again later.';
|
||||||
}
|
}
|
||||||
this.submitStatus = 'send_failed';
|
this.submitStatus = 'send_failed';
|
||||||
console.log(this.submitStatus);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -131,7 +125,6 @@ export class AccountEditComponent implements OnInit {
|
||||||
if (!this.settingForm.valid && !this.settingCustomerForm.valid) {
|
if (!this.settingForm.valid && !this.settingCustomerForm.valid) {
|
||||||
console.log('Not Valid!');
|
console.log('Not Valid!');
|
||||||
this.submitStatus = 'validation_failed';
|
this.submitStatus = 'validation_failed';
|
||||||
console.log(this.submitStatus);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,74 @@
|
||||||
<span class="help-block">Enter the amount spent, such as 5.35 for £5.35.</span>
|
<span class="help-block">Enter the amount spent, such as 5.35 for £5.35.</span>
|
||||||
</div>
|
</div>
|
||||||
</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">
|
<div class="form-group row">
|
||||||
<label class="col-md-3 form-control-label" for="text-input"><strong>Organisation Name</strong></label>
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Organisation Name</strong></label>
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
|
@ -34,21 +102,21 @@
|
||||||
<org-table *ngIf="storeList.length > 0" [orgList]="storeList" (onClick)="addStore($event)"></org-table>
|
<org-table *ngIf="storeList.length > 0" [orgList]="storeList" (onClick)="addStore($event)"></org-table>
|
||||||
<div *ngIf="showAddStore">
|
<div *ngIf="showAddStore">
|
||||||
<div class="form-group row">
|
<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">
|
<div class="col-md-9">
|
||||||
<input type="text" class="form-control" placeholder="Which Street?" [(ngModel)]="submitOrg.street_name" (ngModelChange)="transactionFormValidate()">
|
<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>
|
<span class="help-block">Enter the street name where the organisation is located at.</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group row">
|
<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">
|
<div class="col-md-9">
|
||||||
<input type="text" class="form-control" placeholder="Which Town?" [(ngModel)]="submitOrg.town" (ngModelChange)="transactionFormValidate()">
|
<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>
|
<span class="help-block">Enter the name of the town where the organisation is located at.</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group row">
|
<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">
|
<div class="col-md-9">
|
||||||
<input type="text" class="form-control" placeholder="Postcode if known" [(ngModel)]="submitOrg.postcode" (ngModelChange)="transactionFormValidate()">
|
<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>
|
<span class="help-block">Enter the postcode where the organisation is located at.</span>
|
||||||
|
@ -89,14 +157,14 @@
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-md-3 form-control-label" for="text-input"><strong>Total amount of Employees</strong></label>
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Total amount of Employees</strong></label>
|
||||||
<div class="col-md-9">
|
<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>
|
<span class="help-block">Enter the amount of employees the organisation has for the entry month.</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-md-3 form-control-label" for="text-input"><strong>Total amount of local Employees</strong></label>
|
<label class="col-md-3 form-control-label" for="text-input"><strong>Total amount of local Employees</strong></label>
|
||||||
<div class="col-md-9">
|
<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>
|
<span class="help-block">Enter the amount of employees that live locally to the organisation for the entry month.</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { Validators, FormBuilder, FormGroup } from '@angular/forms';
|
||||||
import { ApiService } from '../providers/api-service';
|
import { ApiService } from '../providers/api-service';
|
||||||
import { OrgTableComponent } from '../shared/org-table.component';
|
import { OrgTableComponent } from '../shared/org-table.component';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
import 'rxjs/add/operator/map';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: 'add-data.component.html',
|
templateUrl: 'add-data.component.html',
|
||||||
|
@ -30,6 +30,9 @@ export class AddDataComponent implements OnInit {
|
||||||
organisationTown: string;
|
organisationTown: string;
|
||||||
organisationPostcode: string;
|
organisationPostcode: string;
|
||||||
amount: number;
|
amount: number;
|
||||||
|
essentialPurchase = false;
|
||||||
|
recurringPurchase = false;
|
||||||
|
recurringType: string;
|
||||||
transactionAdditionType = 1;
|
transactionAdditionType = 1;
|
||||||
storeList = [];
|
storeList = [];
|
||||||
showAddStore = false;
|
showAddStore = false;
|
||||||
|
@ -37,6 +40,11 @@ export class AddDataComponent implements OnInit {
|
||||||
transactionFormInvalid = true;
|
transactionFormInvalid = true;
|
||||||
myDate: any;
|
myDate: any;
|
||||||
minDate: any;
|
minDate: any;
|
||||||
|
categoryList: any;
|
||||||
|
categoryIdList: any;
|
||||||
|
leftCategoryList: number[] = [];
|
||||||
|
rightCategoryList: string[] = [];
|
||||||
|
categoryId: number;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
|
@ -64,6 +72,17 @@ export class AddDataComponent implements OnInit {
|
||||||
});
|
});
|
||||||
this.myDate = moment().format('YYYY-MM-DD[T]HH:mm');
|
this.myDate = moment().format('YYYY-MM-DD[T]HH:mm');
|
||||||
// this.myDate = new Date().toISOString().slice(0, 16);
|
// 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 {
|
ngOnInit(): void {
|
||||||
|
@ -71,6 +90,12 @@ export class AddDataComponent implements OnInit {
|
||||||
this.accountType = localStorage.getItem('usertype');
|
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() {
|
getMinDate() {
|
||||||
// gets the April 1st date of the current year
|
// gets the April 1st date of the current year
|
||||||
const aprilDate = moment().month(3).date(1);
|
const aprilDate = moment().month(3).date(1);
|
||||||
|
@ -149,12 +174,16 @@ export class AddDataComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
transactionFormValidate() {
|
transactionFormValidate() {
|
||||||
if (this.submitOrg.name.length === 0 ||
|
this.transactionFormStatus = null;
|
||||||
this.submitOrg.town.length === 0 ||
|
if (this.submitOrg.name.length &&
|
||||||
this.amount === 0 ) {
|
this.amount &&
|
||||||
this.transactionFormInvalid = true;
|
(this.recurringPurchase &&
|
||||||
} else {
|
this.recurringType ||
|
||||||
|
!this.recurringPurchase &&
|
||||||
|
!this.recurringType)) {
|
||||||
this.transactionFormInvalid = false;
|
this.transactionFormInvalid = false;
|
||||||
|
} else {
|
||||||
|
this.transactionFormInvalid = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,6 +199,9 @@ export class AddDataComponent implements OnInit {
|
||||||
transaction_value : this.amount,
|
transaction_value : this.amount,
|
||||||
purchase_time : purchaseTime,
|
purchase_time : purchaseTime,
|
||||||
organisation_id : this.organisationId,
|
organisation_id : this.organisationId,
|
||||||
|
category : this.categoryId,
|
||||||
|
essential : this.essentialPurchase,
|
||||||
|
recurring : this.recurringType,
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -178,6 +210,9 @@ export class AddDataComponent implements OnInit {
|
||||||
transaction_value : this.amount,
|
transaction_value : this.amount,
|
||||||
purchase_time : purchaseTime,
|
purchase_time : purchaseTime,
|
||||||
organisation_id : this.organisationId,
|
organisation_id : this.organisationId,
|
||||||
|
category : this.categoryId,
|
||||||
|
essential : this.essentialPurchase,
|
||||||
|
recurring : this.recurringType,
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
|
@ -189,6 +224,9 @@ export class AddDataComponent implements OnInit {
|
||||||
street_name : this.submitOrg.street_name,
|
street_name : this.submitOrg.street_name,
|
||||||
town : this.submitOrg.town,
|
town : this.submitOrg.town,
|
||||||
postcode : this.submitOrg.postcode,
|
postcode : this.submitOrg.postcode,
|
||||||
|
category : this.categoryId,
|
||||||
|
essential : this.essentialPurchase,
|
||||||
|
recurring : this.recurringType,
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -199,31 +237,22 @@ export class AddDataComponent implements OnInit {
|
||||||
.subscribe(
|
.subscribe(
|
||||||
result => {
|
result => {
|
||||||
if ( result.success === true ) {
|
if ( result.success === true ) {
|
||||||
console.log('Successful Upload');
|
|
||||||
console.log(result);
|
|
||||||
this.transactionFormStatus = 'success';
|
this.transactionFormStatus = 'success';
|
||||||
console.log(this.transactionFormStatus);
|
|
||||||
this.resetForm();
|
this.resetForm();
|
||||||
} else {
|
} else {
|
||||||
console.log('Upload Error');
|
|
||||||
this.transactionFormStatusError = JSON.stringify(result.status) + 'Error, ' + JSON.stringify(result.message);
|
this.transactionFormStatusError = JSON.stringify(result.status) + 'Error, ' + JSON.stringify(result.message);
|
||||||
this.transactionFormStatus = 'send_failed';
|
this.transactionFormStatus = 'send_failed';
|
||||||
console.log(this.transactionFormStatus);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
console.log('Upload Error');
|
|
||||||
console.log(error);
|
console.log(error);
|
||||||
try {
|
try {
|
||||||
console.log(error.error);
|
console.log(error.error);
|
||||||
const jsonError = error.json();
|
this.transactionFormStatusError = '"' + error.error.error + '" Error, ' + error.error.message;
|
||||||
console.log('boop');
|
|
||||||
this.transactionFormStatusError = '"' + jsonError.error + '" Error, ' + jsonError.message;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.transactionFormStatusError = 'There was a server error, please try again later.';
|
this.transactionFormStatusError = 'There was a server error, please try again later.';
|
||||||
}
|
}
|
||||||
this.transactionFormStatus = 'send_failed';
|
this.transactionFormStatus = 'send_failed';
|
||||||
console.log(this.transactionFormStatus);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -239,6 +268,9 @@ export class AddDataComponent implements OnInit {
|
||||||
this.amount = null;
|
this.amount = null;
|
||||||
this.transactionFormInvalid = true;
|
this.transactionFormInvalid = true;
|
||||||
this.showAddStore = false;
|
this.showAddStore = false;
|
||||||
|
this.essentialPurchase = false;
|
||||||
|
this.recurringPurchase = false;
|
||||||
|
this.recurringType = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
onSubmitPayroll() {
|
onSubmitPayroll() {
|
||||||
|
@ -248,14 +280,11 @@ export class AddDataComponent implements OnInit {
|
||||||
.orgPayroll(this.payrollForm.value)
|
.orgPayroll(this.payrollForm.value)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
result => {
|
result => {
|
||||||
console.log('data submitted!');
|
|
||||||
this.payrollFormStatus = 'success';
|
this.payrollFormStatus = 'success';
|
||||||
console.log(this.payrollFormStatus);
|
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
console.log( error._body );
|
console.log( error._body );
|
||||||
this.payrollFormStatus = 'send_failed';
|
this.payrollFormStatus = 'send_failed';
|
||||||
console.log(this.payrollFormStatus);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -267,14 +296,10 @@ export class AddDataComponent implements OnInit {
|
||||||
.orgSupplier(this.singleSupplierForm.value)
|
.orgSupplier(this.singleSupplierForm.value)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
result => {
|
result => {
|
||||||
console.log('data submitted!');
|
|
||||||
this.singleSupplierFormStatus = 'success';
|
this.singleSupplierFormStatus = 'success';
|
||||||
console.log(this.singleSupplierFormStatus);
|
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
console.log( error._body );
|
|
||||||
this.singleSupplierFormStatus = 'send_failed';
|
this.singleSupplierFormStatus = 'send_failed';
|
||||||
console.log(this.singleSupplierFormStatus);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -286,14 +311,10 @@ export class AddDataComponent implements OnInit {
|
||||||
.orgEmployee(this.employeeForm.value)
|
.orgEmployee(this.employeeForm.value)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
result => {
|
result => {
|
||||||
console.log('data submitted!');
|
|
||||||
this.employeeFormStatus = 'success';
|
this.employeeFormStatus = 'success';
|
||||||
console.log(this.employeeFormStatus);
|
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
console.log( error._body );
|
|
||||||
this.employeeFormStatus = 'send_failed';
|
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="animated fadeIn">
|
||||||
<div class="card">
|
<snippet-bar-cust></snippet-bar-cust>
|
||||||
<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>
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-6 col-lg-3">
|
<div *ngFor="let widget of widgetList" class="col-sm-6 col-lg-3">
|
||||||
<div class="card card-inverse card-primary">
|
<widget-graph *ngIf="widget.type == 'graph'"
|
||||||
<div class="card-block">
|
[graphName]="widget.name"
|
||||||
<div class="h4 mb-0">{{ basicStats.today_sum | currency:'GBP':'symbol':'1.2-2' }}</div>
|
[graphTitle]="widget.title"
|
||||||
<div>Total Today</div>
|
[graphIcon]="widget.icon"
|
||||||
<!-- <div class="progress progress-white progress-xs mt-3">
|
[dataType]="widget.dataType">
|
||||||
<div class="progress-bar" role="progressbar" style="width: 100%" attr.aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
|
</widget-graph>
|
||||||
</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><!--/.col-->
|
</div><!--/.col-->
|
||||||
</div><!--/.row-->
|
</div><!--/.row-->
|
||||||
|
<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>
|
</div>
|
||||||
|
|
|
@ -1,16 +1,25 @@
|
||||||
import { Directive, Component, OnInit } from '@angular/core';
|
import { Directive, Component, OnInit } from '@angular/core';
|
||||||
|
import { CurrencyPipe } from '@angular/common';
|
||||||
import { ApiService } from '../providers/api-service';
|
import { ApiService } from '../providers/api-service';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
import { ChartOptions, ChartType, ChartDataSets } from 'chart.js';
|
||||||
import { GraphWidget } from '../widgets/graph-widget.component';
|
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({
|
@Component({
|
||||||
templateUrl: 'dashboard-customer.component.html'
|
templateUrl: 'dashboard-customer.component.html'
|
||||||
})
|
})
|
||||||
export class DashboardCustomerComponent implements OnInit {
|
export class DashboardCustomerComponent implements OnInit {
|
||||||
customersThisMonth: any;
|
|
||||||
moneySpentThisMonth: any;
|
|
||||||
pointsTotal: any;
|
|
||||||
averageTransactionToday: any;
|
|
||||||
|
|
||||||
/* Setting up dashboard's main variables*/
|
/* Setting up dashboard's main variables*/
|
||||||
name: any;
|
name: any;
|
||||||
|
@ -19,27 +28,178 @@ export class DashboardCustomerComponent implements OnInit {
|
||||||
trends: any;
|
trends: any;
|
||||||
myRank: any;
|
myRank: any;
|
||||||
username: any;
|
username: any;
|
||||||
|
maxPurchase: number = 0;
|
||||||
|
|
||||||
basicStats = {
|
disableCategoryButton: boolean = false;
|
||||||
today_sum: 0,
|
|
||||||
today_count: 0,
|
public bootstrapColours: string[] = ['bg-primary', 'bg-secondary', 'bg-success',
|
||||||
week_sum: 0,
|
'bg-danger', 'bg-warning', 'bg-info'];
|
||||||
week_count: 0,
|
|
||||||
month_sum: 0,
|
public chartType = 'doughnut';
|
||||||
month_count: 0,
|
public chartLegend = true;
|
||||||
user_sum: 0,
|
public doughnutChartDataCategory: any[] = [];
|
||||||
user_count: 0,
|
public doughnutChartLabelsCategory: string[] = [];
|
||||||
global_sum: 0,
|
public doughnutChartColoursCategory: any[] = [
|
||||||
global_count: 0,
|
{
|
||||||
user_position: 0,
|
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(
|
constructor(
|
||||||
private api: ApiService,
|
private api: ApiService,
|
||||||
|
private currencyPipe: CurrencyPipe,
|
||||||
) {
|
) {
|
||||||
this.api.basicStats().subscribe(
|
this.setDate();
|
||||||
|
this.api.customerStats().subscribe(
|
||||||
result => {
|
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 => {
|
error => {
|
||||||
console.log('Retrieval 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 {
|
ngOnInit(): void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
<div class="animated fadeIn">
|
<div class="animated fadeIn">
|
||||||
<snippet-bar-org></snippet-bar-org>
|
<snippet-bar-org></snippet-bar-org>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -6,8 +7,107 @@
|
||||||
[graphName]="widget.name"
|
[graphName]="widget.name"
|
||||||
[graphTitle]="widget.title"
|
[graphTitle]="widget.title"
|
||||||
[graphIcon]="widget.icon"
|
[graphIcon]="widget.icon"
|
||||||
[dataType]="widget.dataType"></widget-graph>
|
[dataType]="widget.dataType">
|
||||||
|
</widget-graph>
|
||||||
</div><!--/.col-->
|
</div><!--/.col-->
|
||||||
</div><!--/.row-->
|
</div><!--/.row-->
|
||||||
<panel-graph></panel-graph>
|
<panel-graph></panel-graph>
|
||||||
|
<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>
|
</div>
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
import { Component } from '@angular/core';
|
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 { GraphWidget } from '../widgets/graph-widget.component';
|
||||||
import { OrgBarSnippetComponent } from '../snippets/org-snippet-bar.component';
|
import { OrgBarSnippetComponent } from '../snippets/org-snippet-bar.component';
|
||||||
import { GraphPanel } from '../panels/graph-panel.component';
|
import { GraphPanel } from '../panels/graph-panel.component';
|
||||||
|
import { OrgPiePanel } from '../panels/org-pie-panel.component';
|
||||||
import { DataType } from '../shared/data-types.enum';
|
import { DataType } from '../shared/data-types.enum';
|
||||||
|
import { ApiService } from '../providers/api-service';
|
||||||
|
import { environment } from '../../environments/environment';
|
||||||
|
import * as moment from 'moment';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: 'dashboard.component.html'
|
templateUrl: 'dashboard.component.html'
|
||||||
|
@ -37,6 +44,13 @@ export class DashboardComponent {
|
||||||
title: 'Sales Last 30 Days',
|
title: 'Sales Last 30 Days',
|
||||||
dataType: DataType.currency,
|
dataType: DataType.currency,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'graph',
|
||||||
|
name: 'sales_last_quart',
|
||||||
|
icon: 'icon-diamond',
|
||||||
|
title: 'Sales Last Quart',
|
||||||
|
dataType: DataType.currency,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: 'graph',
|
type: 'graph',
|
||||||
name: 'purchases_last_7_days',
|
name: 'purchases_last_7_days',
|
||||||
|
@ -49,7 +63,307 @@ export class DashboardComponent {
|
||||||
title: 'Purchases Last 30 Days',
|
title: 'Purchases Last 30 Days',
|
||||||
dataType: DataType.currency,
|
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 { NgModule } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
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 { BsDropdownModule } from 'ngx-bootstrap/dropdown';
|
||||||
import { NgxPaginationModule } from 'ngx-pagination';
|
import { NgxPaginationModule } from 'ngx-pagination';
|
||||||
import { AgmCoreModule, GoogleMapsAPIWrapper } from '@agm/core';
|
import { AgmCoreModule, GoogleMapsAPIWrapper } from '@agm/core';
|
||||||
|
@ -16,19 +16,31 @@ import { AccountEditComponent } from './account-edit.component';
|
||||||
import { AddDataComponent } from './add-data.component';
|
import { AddDataComponent } from './add-data.component';
|
||||||
import { FeedbackComponent } from './feedback.component';
|
import { FeedbackComponent } from './feedback.component';
|
||||||
import { TransactionLogComponent } from './transaction-log.component';
|
import { TransactionLogComponent } from './transaction-log.component';
|
||||||
|
import { CategoryMonthComponent } from './category-month.component';
|
||||||
import { PayrollLogComponent } from './payroll-log.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 { LeaderboardComponent } from './leaderboard.component';
|
||||||
import { MapComponent } from './map.component';
|
import { MapComponent } from './map.component';
|
||||||
import { TrailMapComponent } from './trail-map.component';
|
import { TrailMapComponent } from './trail-map.component';
|
||||||
|
|
||||||
import { GraphWidget } from '../widgets/graph-widget.component';
|
import { GraphWidget } from '../widgets/graph-widget.component';
|
||||||
import { OrgBarSnippetComponent } from '../snippets/org-snippet-bar.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 { 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 { DashboardRoutingModule } from './dashboard.routing';
|
||||||
import { OrgResultComponent } from '../shared/org-result.component';
|
import { OrgResultComponent } from '../shared/org-result.component';
|
||||||
import { OrgTableComponent } from '../shared/org-table.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 { 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 { PayrollResultComponent } from '../shared/payroll-result.component';
|
||||||
import { LeaderboardResultComponent } from '../shared/leaderboard-result.component';
|
import { LeaderboardResultComponent } from '../shared/leaderboard-result.component';
|
||||||
|
|
||||||
|
@ -58,8 +70,14 @@ import { environment } from '../../environments/environment';
|
||||||
AddDataComponent,
|
AddDataComponent,
|
||||||
OrgResultComponent,
|
OrgResultComponent,
|
||||||
OrgTableComponent,
|
OrgTableComponent,
|
||||||
|
RecurResultComponent,
|
||||||
|
RecurTableComponent,
|
||||||
TransactionLogComponent,
|
TransactionLogComponent,
|
||||||
|
CategoryMonthComponent,
|
||||||
TransactionResultComponent,
|
TransactionResultComponent,
|
||||||
|
SupplierResultComponent,
|
||||||
|
WardResultComponent,
|
||||||
|
MetaTypeResultComponent,
|
||||||
PayrollLogComponent,
|
PayrollLogComponent,
|
||||||
PayrollResultComponent,
|
PayrollResultComponent,
|
||||||
LeaderboardComponent,
|
LeaderboardComponent,
|
||||||
|
@ -69,7 +87,13 @@ import { environment } from '../../environments/environment';
|
||||||
FeedbackComponent,
|
FeedbackComponent,
|
||||||
GraphWidget,
|
GraphWidget,
|
||||||
OrgBarSnippetComponent,
|
OrgBarSnippetComponent,
|
||||||
|
CustBarSnippetComponent,
|
||||||
GraphPanel,
|
GraphPanel,
|
||||||
|
PiePanel,
|
||||||
|
OrgPiePanel,
|
||||||
|
BubbleChartComponent,
|
||||||
|
SuppliersComponent,
|
||||||
|
MoreStuffComponent,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
CurrencyPipe,
|
CurrencyPipe,
|
||||||
|
|
|
@ -12,10 +12,13 @@ import { AccountEditComponent } from './account-edit.component';
|
||||||
import { AddDataComponent } from './add-data.component';
|
import { AddDataComponent } from './add-data.component';
|
||||||
import { FeedbackComponent } from './feedback.component';
|
import { FeedbackComponent } from './feedback.component';
|
||||||
import { TransactionLogComponent } from './transaction-log.component';
|
import { TransactionLogComponent } from './transaction-log.component';
|
||||||
|
import { CategoryMonthComponent } from './category-month.component';
|
||||||
import { PayrollLogComponent } from './payroll-log.component';
|
import { PayrollLogComponent } from './payroll-log.component';
|
||||||
import { LeaderboardComponent } from './leaderboard.component';
|
import { LeaderboardComponent } from './leaderboard.component';
|
||||||
import { MapComponent } from './map.component';
|
import { MapComponent } from './map.component';
|
||||||
import { TrailMapComponent } from './trail-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
|
// Using child path to allow for FullLayout theming
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
|
@ -58,6 +61,11 @@ const routes: Routes = [
|
||||||
component: TransactionLogComponent,
|
component: TransactionLogComponent,
|
||||||
data: { title: 'Transaction Log' },
|
data: { title: 'Transaction Log' },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'category-month',
|
||||||
|
component: CategoryMonthComponent,
|
||||||
|
data: { title: 'Budget' },
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'map',
|
path: 'map',
|
||||||
component: MapComponent,
|
component: MapComponent,
|
||||||
|
@ -66,7 +74,7 @@ const routes: Routes = [
|
||||||
{
|
{
|
||||||
path: 'story-trail',
|
path: 'story-trail',
|
||||||
component: TrailMapComponent,
|
component: TrailMapComponent,
|
||||||
data: { title: 'Lancaster Independent Story' },
|
data: { title: 'Story Trail' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'payroll-log',
|
path: 'payroll-log',
|
||||||
|
@ -78,6 +86,16 @@ const routes: Routes = [
|
||||||
path: 'feedback',
|
path: 'feedback',
|
||||||
component: FeedbackComponent,
|
component: FeedbackComponent,
|
||||||
data: { title: 'Give Feedback' },
|
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 { Component, OnInit } from '@angular/core';
|
||||||
import { Validators, FormBuilder, FormGroup } from '@angular/forms';
|
import { Validators, FormBuilder, FormGroup } from '@angular/forms';
|
||||||
import { ApiService } from '../providers/api-service';
|
import { ApiService } from '../providers/api-service';
|
||||||
import 'rxjs/add/operator/map';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: 'feedback.component.html',
|
templateUrl: 'feedback.component.html',
|
||||||
|
@ -55,9 +55,7 @@ export class FeedbackComponent implements OnInit {
|
||||||
result => {
|
result => {
|
||||||
if ( result.success === true ) {
|
if ( result.success === true ) {
|
||||||
console.log('Successful Upload');
|
console.log('Successful Upload');
|
||||||
console.log(result);
|
|
||||||
this.feedbackFormStatus = 'success';
|
this.feedbackFormStatus = 'success';
|
||||||
console.log(this.feedbackFormStatus);
|
|
||||||
this.feedbackForm.patchValue({
|
this.feedbackForm.patchValue({
|
||||||
feedbacktext: '',
|
feedbacktext: '',
|
||||||
});
|
});
|
||||||
|
@ -65,22 +63,16 @@ export class FeedbackComponent implements OnInit {
|
||||||
console.log('Upload Error');
|
console.log('Upload Error');
|
||||||
this.feedbackFormStatusError = JSON.stringify(result.status) + 'Error, ' + JSON.stringify(result.message);
|
this.feedbackFormStatusError = JSON.stringify(result.status) + 'Error, ' + JSON.stringify(result.message);
|
||||||
this.feedbackFormStatus = 'send_failed';
|
this.feedbackFormStatus = 'send_failed';
|
||||||
console.log(this.feedbackFormStatus);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
console.log('Upload Error');
|
console.log('Upload Error');
|
||||||
console.log(error);
|
|
||||||
try {
|
try {
|
||||||
console.log(error.error);
|
this.feedbackFormStatusError = '"' + error.error.error + '" Error, ' + error.error.message;
|
||||||
const jsonError = error.json();
|
|
||||||
console.log('boop');
|
|
||||||
this.feedbackFormStatusError = '"' + jsonError.error + '" Error, ' + jsonError.message;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.feedbackFormStatusError = 'There was a server error, please try again later.';
|
this.feedbackFormStatusError = 'There was a server error, please try again later.';
|
||||||
}
|
}
|
||||||
this.feedbackFormStatus = 'send_failed';
|
this.feedbackFormStatus = 'send_failed';
|
||||||
console.log(this.feedbackFormStatus);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,8 @@
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Position</th>
|
<th>Position</th>
|
||||||
<th>Value</th>
|
<th>Name</th>
|
||||||
<th>Purchase Time</th>
|
<th class="js-sort-number">Gross amount</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {PaginationInstance} from 'ngx-pagination';
|
||||||
// import { PaginationControlsComponent } from 'ngx-pagination';
|
// import { PaginationControlsComponent } from 'ngx-pagination';
|
||||||
// import { PaginationControlsDirective } from 'ngx-pagination';
|
// import { PaginationControlsDirective } from 'ngx-pagination';
|
||||||
// import { TransactionResultComponent } from '../shared/transaction-result.component';
|
// import { TransactionResultComponent } from '../shared/transaction-result.component';
|
||||||
import 'rxjs/add/operator/map';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: 'leaderboard.component.html',
|
templateUrl: 'leaderboard.component.html',
|
||||||
|
@ -22,7 +22,7 @@ export class LeaderboardComponent implements OnInit {
|
||||||
|
|
||||||
public paginateConfig: PaginationInstance = {
|
public paginateConfig: PaginationInstance = {
|
||||||
id: 'leadpaginate',
|
id: 'leadpaginate',
|
||||||
itemsPerPage: 10,
|
itemsPerPage: 20,
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
totalItems: 0
|
totalItems: 0
|
||||||
};
|
};
|
||||||
|
@ -70,7 +70,7 @@ export class LeaderboardComponent implements OnInit {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}org
|
||||||
|
|
||||||
// // dynamically changes the row style based on player's position
|
// // dynamically changes the row style based on player's position
|
||||||
// // for instance, top three player and the player him/herself should
|
// // for instance, top three player and the player him/herself should
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<strong>Lancaster Independent Story</strong>
|
<strong>Purchase Map</strong>
|
||||||
<small>Required Data marked in <strong>bold</strong>.</small>
|
<small>Click a marker to get location details.</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal fade" bsModal #statusModal="bs-modal" [config]="{backdrop: false, animated: false}"
|
<div class="modal fade" bsModal #statusModal="bs-modal" [config]="{backdrop: false, animated: false}"
|
||||||
tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
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 { AgmCoreModule } from '@agm/core';
|
||||||
import { BsModalService, ModalDirective } from 'ngx-bootstrap/modal';
|
import { BsModalService, ModalDirective } from 'ngx-bootstrap/modal';
|
||||||
import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';
|
import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';
|
||||||
import 'rxjs/add/operator/map';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: 'map.component.html',
|
templateUrl: 'map.component.html',
|
||||||
})
|
})
|
||||||
export class MapComponent implements OnInit, AfterViewInit {
|
export class MapComponent implements OnInit, AfterViewInit {
|
||||||
@ViewChild('statusModal') myStatusModal: ModalDirective;
|
@ViewChild('statusModal', { static: true }) myStatusModal: ModalDirective;
|
||||||
lat: number = 54.0466;
|
lat: number = 54.0466;
|
||||||
lng: number = -2.8007;
|
lng: number = -2.8007;
|
||||||
zoom: number = 12;
|
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 { PaginationControlsDirective } from 'ngx-pagination';
|
||||||
// import { TransactionResultComponent } from '../shared/transaction-result.component';
|
// import { TransactionResultComponent } from '../shared/transaction-result.component';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
import 'rxjs/add/operator/map';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: 'payroll-log.component.html',
|
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="col-lg-12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<strong>Purchase Map</strong>
|
<strong>Story Trail</strong>
|
||||||
<small>Required Data marked in <strong>bold</strong>.</small>
|
<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>
|
||||||
<div class="modal fade" bsModal #statusModal="bs-modal" [config]="{backdrop: false, animated: false}"
|
<div class="modal fade" bsModal #statusModal="bs-modal" [config]="{backdrop: false, animated: false}"
|
||||||
tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
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-cluster maxZoom="13" imagePath="https://raw.githubusercontent.com/googlemaps/v3-utility-library/master/markerclustererplus/images/m">
|
||||||
<agm-marker
|
<agm-marker
|
||||||
*ngFor="let m of markers"
|
*ngFor="let m of markers"
|
||||||
[iconUrl]="'/assets/img/map-pin-lis.png'"
|
[iconUrl]="'/assets/img/association/' + assocMap + '-map-pin.png'"
|
||||||
[latitude]="m.latitude"
|
[latitude]="m.latitude"
|
||||||
[longitude]="m.longitude"
|
[longitude]="m.longitude"
|
||||||
[openInfoWindow]="false"
|
[openInfoWindow]="false"
|
||||||
|
@ -55,7 +87,7 @@
|
||||||
</agm-map>
|
</agm-map>
|
||||||
<ng-template #template>
|
<ng-template #template>
|
||||||
<div class="modal-header d-flex justify-content-between">
|
<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()">
|
<button type="button" class="close pull-right" aria-label="Close" (click)="modalRef.hide()">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -3,18 +3,21 @@ import { ApiService } from '../providers/api-service';
|
||||||
import { AgmCoreModule } from '@agm/core';
|
import { AgmCoreModule } from '@agm/core';
|
||||||
import { BsModalService, ModalDirective } from 'ngx-bootstrap/modal';
|
import { BsModalService, ModalDirective } from 'ngx-bootstrap/modal';
|
||||||
import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';
|
import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';
|
||||||
import 'rxjs/add/operator/map';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: 'trail-map.component.html',
|
templateUrl: 'trail-map.component.html',
|
||||||
})
|
})
|
||||||
export class TrailMapComponent implements OnInit, AfterViewInit {
|
export class TrailMapComponent implements OnInit, AfterViewInit {
|
||||||
@ViewChild('statusModal') myStatusModal: ModalDirective;
|
@ViewChild('statusModal', { static: true }) myStatusModal: ModalDirective;
|
||||||
lat: number = 54.0466;
|
lat: number = 54.0466;
|
||||||
lng: number = -2.8007;
|
lng: number = -2.8007;
|
||||||
zoom: number = 12;
|
zoom: number = 12;
|
||||||
public modalRef: BsModalRef;
|
public modalRef: BsModalRef;
|
||||||
|
public modalRef2: BsModalRef;
|
||||||
clickedMarker: any;
|
clickedMarker: any;
|
||||||
|
assocMap = 'lis';
|
||||||
|
assocLogo: string;
|
||||||
|
|
||||||
dataReceived: string = 'loading';
|
dataReceived: string = 'loading';
|
||||||
|
|
||||||
|
@ -25,7 +28,9 @@ export class TrailMapComponent implements OnInit, AfterViewInit {
|
||||||
constructor(
|
constructor(
|
||||||
private api: ApiService,
|
private api: ApiService,
|
||||||
private modalService: BsModalService,
|
private modalService: BsModalService,
|
||||||
) {}
|
) {
|
||||||
|
this.assocLogo = 'assets/img/association/' + this.assocMap + '-logo.png';
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void { }
|
ngOnInit(): void { }
|
||||||
|
|
||||||
|
@ -41,9 +46,13 @@ export class TrailMapComponent implements OnInit, AfterViewInit {
|
||||||
this.modalRef = this.modalService.show(template);
|
this.modalRef = this.modalService.show(template);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openModalAssoc(templateAssoc: TemplateRef<any>) {
|
||||||
|
this.modalRef2 = this.modalService.show(templateAssoc);
|
||||||
|
}
|
||||||
|
|
||||||
public onMarkerClick(clickedMarker, template: TemplateRef<any>) {
|
public onMarkerClick(clickedMarker, template: TemplateRef<any>) {
|
||||||
console.log(clickedMarker);
|
|
||||||
this.clickedMarker = clickedMarker;
|
this.clickedMarker = clickedMarker;
|
||||||
|
this.assocLogo = 'assets/img/association/' + this.assocMap + '-logo.png';
|
||||||
this.openModal(template);
|
this.openModal(template);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,8 +73,9 @@ export class TrailMapComponent implements OnInit, AfterViewInit {
|
||||||
latitude: resp.getSouthWest().lat(),
|
latitude: resp.getSouthWest().lat(),
|
||||||
longitude: resp.getSouthWest().lng()
|
longitude: resp.getSouthWest().lng()
|
||||||
},
|
},
|
||||||
|
association: this.assocMap,
|
||||||
}
|
}
|
||||||
this.api.getLisData(mapData).subscribe(
|
this.api.getAssocData(mapData).subscribe(
|
||||||
result => {
|
result => {
|
||||||
this.myStatusModal.hide();
|
this.myStatusModal.hide();
|
||||||
this.markers = result.locations;
|
this.markers = result.locations;
|
||||||
|
|
|
@ -1,22 +1,124 @@
|
||||||
<div class="animated fadeIn">
|
<div class="animated fadeIn">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12">
|
<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">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<strong>Log of Outgoing Transactions</strong>
|
<strong>Log of Outgoing Transactions</strong>
|
||||||
<small>This lists all purchases that have been submitted.</small>
|
<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>
|
||||||
<div *ngIf="!noTransactionList" class="card-block">
|
<div *ngIf="!noTransactionList" class="card-block">
|
||||||
<table class="table table-striped table-hover">
|
<table class="table table-striped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Seller</th>
|
<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>
|
<th>Purchase Time</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<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>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<pagination-template #p="paginationApi"
|
<pagination-template #p="paginationApi"
|
||||||
|
|
|
@ -1,23 +1,35 @@
|
||||||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
import { Component, OnInit, EventEmitter, TemplateRef } from '@angular/core';
|
||||||
import { ApiService } from '../providers/api-service';
|
import { ApiService } from '../providers/api-service';
|
||||||
// import { PaginatePipe } from 'ngx-pagination';
|
import { BsModalService, ModalDirective } from 'ngx-bootstrap/modal';
|
||||||
|
import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';
|
||||||
import { PaginationInstance } from 'ngx-pagination';
|
import { PaginationInstance } from 'ngx-pagination';
|
||||||
// import { PaginationControlsComponent } from 'ngx-pagination';
|
|
||||||
// import { PaginationControlsDirective } from 'ngx-pagination';
|
|
||||||
// import { TransactionResultComponent } from '../shared/transaction-result.component';
|
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
import 'rxjs/add/operator/map';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: 'transaction-log.component.html',
|
templateUrl: 'transaction-log.component.html',
|
||||||
})
|
})
|
||||||
export class TransactionLogComponent implements OnInit {
|
export class TransactionLogComponent implements OnInit {
|
||||||
|
|
||||||
transactionList;
|
transactionList: any;
|
||||||
|
recurringTransactionList: any;
|
||||||
noTransactionList = true;
|
noTransactionList = true;
|
||||||
|
noRecurringList = true;
|
||||||
myDate: any;
|
myDate: any;
|
||||||
minDate: any;
|
minDate: any;
|
||||||
public p: 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 = {
|
public paginateConfig: PaginationInstance = {
|
||||||
id: 'transpaginate',
|
id: 'transpaginate',
|
||||||
|
@ -28,31 +40,27 @@ export class TransactionLogComponent implements OnInit {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private api: ApiService,
|
private api: ApiService,
|
||||||
|
private modalService: BsModalService,
|
||||||
) {
|
) {
|
||||||
this.myDate = moment().format('YYYY-MM-DD[T]HH:mm');
|
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);
|
// this.myDate = new Date().toISOString().slice(0, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.getMinDate();
|
|
||||||
this.loadTransactions(1);
|
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) {
|
loadTransactions(logPage: number) {
|
||||||
console.log(logPage);
|
|
||||||
this.api.transList(logPage).subscribe(
|
this.api.transList(logPage).subscribe(
|
||||||
result => {
|
result => {
|
||||||
if (result.transactions.length > 0) {
|
if (result.transactions.length > 0) {
|
||||||
|
@ -66,6 +74,13 @@ export class TransactionLogComponent implements OnInit {
|
||||||
this.transactionList = null;
|
this.transactionList = null;
|
||||||
this.noTransactionList = true;
|
this.noTransactionList = true;
|
||||||
}
|
}
|
||||||
|
if (result.recurring_transactions) {
|
||||||
|
this.recurringTransactionList = result.recurring_transactions;
|
||||||
|
this.noRecurringList = false;
|
||||||
|
} else {
|
||||||
|
this.recurringTransactionList = null;
|
||||||
|
this.noRecurringList = true;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
console.log(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,44 +25,97 @@
|
||||||
<div class="sidebar">
|
<div class="sidebar">
|
||||||
<nav class="sidebar-nav">
|
<nav class="sidebar-nav">
|
||||||
<ul class="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">
|
<li class="nav-item">
|
||||||
<a class="nav-link" routerLinkActive="active" [routerLink]="['/dashboard']">
|
<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>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" routerLinkActive="active" [routerLink]="['/add-data']">
|
<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>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" routerLinkActive="active" [routerLink]="['/feedback']">
|
<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>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" routerLinkActive="active" [routerLink]="['/map']">
|
<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>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" routerLinkActive="active" [routerLink]="['/story-trail']">
|
<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>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li *ngIf="accountType == 'customer'" class="nav-item">
|
<li *ngIf="accountType == 'customer'" class="nav-item">
|
||||||
<a class="nav-link" routerLinkActive="active" [routerLink]="['/leaderboard']">
|
<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>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" routerLinkActive="active" [routerLink]="['/transaction-log']">
|
<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 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>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li *ngIf="accountType == 'organisation'" class="nav-item">
|
<li *ngIf="accountType == 'organisation'" class="nav-item">
|
||||||
<a class="nav-link" routerLinkActive="active" [routerLink]="['/payroll-log']">
|
<a class="nav-link" routerLinkActive="active" [routerLink]="['/payroll-log']">
|
||||||
<i class="icon-basket"></i> 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>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -39,7 +39,6 @@ export class FullLayoutComponent implements OnInit {
|
||||||
.logout()
|
.logout()
|
||||||
.subscribe(
|
.subscribe(
|
||||||
result => {
|
result => {
|
||||||
console.log('Logged out!');
|
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
this.router.navigate(['/login']);
|
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">
|
||||||
<div class="card-block">
|
<div class="card-block">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-5">
|
<div class="col-sm-12">
|
||||||
<h4 class="card-title mb-0">Customers</h4>
|
<h4 class="card-title mb-0">Customers</h4>
|
||||||
</div><!--/.col-->
|
</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><!--/.row-->
|
||||||
<div class="chart-wrapper" style="height:300px;margin-top:40px;">
|
<div class="chart-wrapper" style="height:300px;margin-top:40px;">
|
||||||
<canvas baseChart class="chart"
|
<canvas baseChart class="chart"
|
||||||
|
|
|
@ -82,12 +82,12 @@ export class GraphPanel implements OnInit {
|
||||||
pointHoverBackgroundColor: '#fff'
|
pointHoverBackgroundColor: '#fff'
|
||||||
},
|
},
|
||||||
{ // brandSuccess
|
{ // brandSuccess
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: this.convertHex(this.brandInfo, 10),
|
||||||
borderColor: this.brandSuccess,
|
borderColor: this.brandSuccess,
|
||||||
pointHoverBackgroundColor: '#fff'
|
pointHoverBackgroundColor: '#fff'
|
||||||
},
|
},
|
||||||
{ // brandDanger
|
{ // brandDanger
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: this.convertHex(this.brandDanger, 10),
|
||||||
borderColor: this.brandDanger,
|
borderColor: this.brandDanger,
|
||||||
pointHoverBackgroundColor: '#fff',
|
pointHoverBackgroundColor: '#fff',
|
||||||
borderWidth: 1,
|
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 { Injectable } from '@angular/core';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Observable } from 'rxjs/Rx';
|
|
||||||
import { environment } from '../../environments/environment';
|
import { environment } from '../../environments/environment';
|
||||||
import 'rxjs/add/operator/map';
|
|
||||||
|
|
||||||
/* this provider handles the interaction between server and client */
|
/* this provider handles the interaction between server and client */
|
||||||
|
|
||||||
|
@ -29,18 +29,15 @@ export class ApiService {
|
||||||
// Login API
|
// Login API
|
||||||
|
|
||||||
public getSessionKey() {
|
public getSessionKey() {
|
||||||
console.log('get key');
|
|
||||||
return this.sessionKey;
|
return this.sessionKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setSessionKey(key) {
|
public setSessionKey(key) {
|
||||||
console.log('set key');
|
|
||||||
this.sessionKey = key;
|
this.sessionKey = key;
|
||||||
localStorage.setItem('sessionKey', this.sessionKey);
|
localStorage.setItem('sessionKey', this.sessionKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeSessionKey() {
|
public removeSessionKey() {
|
||||||
console.log('remove key');
|
|
||||||
this.sessionKey = null;
|
this.sessionKey = null;
|
||||||
localStorage.removeItem('sessionKey');
|
localStorage.removeItem('sessionKey');
|
||||||
}
|
}
|
||||||
|
@ -57,8 +54,8 @@ export class ApiService {
|
||||||
.post<any>(
|
.post<any>(
|
||||||
this.apiUrl + '/login',
|
this.apiUrl + '/login',
|
||||||
data
|
data
|
||||||
)
|
).pipe(
|
||||||
.map(
|
map(
|
||||||
result => {
|
result => {
|
||||||
const json = result;
|
const json = result;
|
||||||
this.setSessionKey(json.session_key);
|
this.setSessionKey(json.session_key);
|
||||||
|
@ -69,24 +66,23 @@ export class ApiService {
|
||||||
this.setUserType(json.user_type);
|
this.setUserType(json.user_type);
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
public logout() {
|
public logout() {
|
||||||
console.log(this.sessionKey);
|
|
||||||
const key = this.sessionKey;
|
const key = this.sessionKey;
|
||||||
return this.http
|
return this.http
|
||||||
.post<any>(
|
.post<any>(
|
||||||
this.apiUrl + '/logout',
|
this.apiUrl + '/logout',
|
||||||
{ session_key : key },
|
{ session_key : key },
|
||||||
)
|
).pipe(
|
||||||
.map(
|
map(
|
||||||
response => {
|
response => {
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
this.sessionKey = null;
|
this.sessionKey = null;
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submits feedback
|
// Submits feedback
|
||||||
|
@ -96,7 +92,6 @@ export class ApiService {
|
||||||
data.package_name = 'Foodloop Web';
|
data.package_name = 'Foodloop Web';
|
||||||
data.version_code = 'dev';
|
data.version_code = 'dev';
|
||||||
data.version_number = 'dev';
|
data.version_number = 'dev';
|
||||||
console.log(data);
|
|
||||||
return this.http.post<any>(
|
return this.http.post<any>(
|
||||||
this.apiUrl + '/feedback',
|
this.apiUrl + '/feedback',
|
||||||
data
|
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
|
// Searches organisations used for transaction submission
|
||||||
|
|
||||||
public search(data) {
|
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
|
// gets payroll list for log
|
||||||
|
|
||||||
public payrollList(data) {
|
public payrollList(data) {
|
||||||
|
@ -188,7 +262,6 @@ export class ApiService {
|
||||||
public setUserInfo(
|
public setUserInfo(
|
||||||
email: string,
|
email: string,
|
||||||
display_name: string) {
|
display_name: string) {
|
||||||
console.log('set UserInfo');
|
|
||||||
localStorage.setItem('email', email);
|
localStorage.setItem('email', email);
|
||||||
localStorage.setItem('displayname', display_name);
|
localStorage.setItem('displayname', display_name);
|
||||||
}
|
}
|
||||||
|
@ -196,7 +269,6 @@ export class ApiService {
|
||||||
// Sets usertype
|
// Sets usertype
|
||||||
|
|
||||||
public setUserType(user_type: string) {
|
public setUserType(user_type: string) {
|
||||||
console.log('set UserType');
|
|
||||||
localStorage.setItem('usertype', user_type);
|
localStorage.setItem('usertype', user_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,33 +293,27 @@ export class ApiService {
|
||||||
// Deletes account details on logout
|
// Deletes account details on logout
|
||||||
|
|
||||||
public removeUserInfo() {
|
public removeUserInfo() {
|
||||||
console.log('remove UserInfo');
|
|
||||||
localStorage.removeItem('email');
|
localStorage.removeItem('email');
|
||||||
localStorage.removeItem('displayname');
|
localStorage.removeItem('displayname');
|
||||||
}
|
}
|
||||||
|
|
||||||
public getFullName() {
|
public getFullName() {
|
||||||
console.log('get Full Name');
|
|
||||||
localStorage.getItem('fullname');
|
localStorage.getItem('fullname');
|
||||||
}
|
}
|
||||||
|
|
||||||
public getDisplayName() {
|
public getDisplayName() {
|
||||||
console.log('get Display Name');
|
|
||||||
localStorage.getItem('displayname');
|
localStorage.getItem('displayname');
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPostcode() {
|
public getPostcode() {
|
||||||
console.log('get Postcode');
|
|
||||||
localStorage.getItem('postcode');
|
localStorage.getItem('postcode');
|
||||||
}
|
}
|
||||||
|
|
||||||
public getYearOfBirth() {
|
public getYearOfBirth() {
|
||||||
console.log('get Year of Birth');
|
|
||||||
localStorage.getItem('yearofbirth');
|
localStorage.getItem('yearofbirth');
|
||||||
}
|
}
|
||||||
|
|
||||||
public getEmail() {
|
public getEmail() {
|
||||||
console.log('get email');
|
|
||||||
localStorage.getItem('email');
|
localStorage.getItem('email');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,20 +342,31 @@ export class ApiService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load LIS Data
|
// Load Association Data
|
||||||
public getLisData(data) {
|
public getAssocData(data) {
|
||||||
data.session_key = this.sessionKey;
|
data.session_key = this.sessionKey;
|
||||||
return this.http.post<any>(
|
return this.http.post<any>(
|
||||||
this.apiUrl + '/v1/supplier/location/lis',
|
this.apiUrl + '/v1/supplier/location/trail',
|
||||||
data
|
data
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Basic Customer User stats API
|
// Basic Customer User stats API
|
||||||
public basicStats() {
|
public customerStats() {
|
||||||
const key = this.sessionKey;
|
const key = this.sessionKey;
|
||||||
return this.http.post<any>(
|
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,
|
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 { Injectable } from '@angular/core';
|
||||||
import { ApiService } from './api-service';
|
import { ApiService } from './api-service';
|
||||||
import { Observable } from 'rxjs/Rx';
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class OrgSnippetsService {
|
export class OrgSnippetsService {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
|
||||||
|
import {filter} from 'rxjs/operators';
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
|
import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
|
||||||
import 'rxjs/add/operator/filter';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-breadcrumbs',
|
selector: 'app-breadcrumbs',
|
||||||
|
@ -18,7 +20,7 @@ export class BreadcrumbsComponent implements OnInit {
|
||||||
breadcrumbs: Array<Object>;
|
breadcrumbs: Array<Object>;
|
||||||
constructor(private router: Router, private route: ActivatedRoute) {}
|
constructor(private router: Router, private route: ActivatedRoute) {}
|
||||||
ngOnInit(): void {
|
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 = [];
|
this.breadcrumbs = [];
|
||||||
let currentRoute = this.route.root,
|
let currentRoute = this.route.root,
|
||||||
url = '';
|
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.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>
|
<td>{{transactionDate}}</td>
|
||||||
|
|
|
@ -14,6 +14,7 @@ interface TransactionData {
|
||||||
})
|
})
|
||||||
export class TransactionResultComponent implements OnInit {
|
export class TransactionResultComponent implements OnInit {
|
||||||
@Input() public transaction: TransactionData;
|
@Input() public transaction: TransactionData;
|
||||||
|
@Input() public showMeta: boolean;
|
||||||
public transactionDate: string;
|
public transactionDate: string;
|
||||||
|
|
||||||
ngOnInit(): void {
|
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">
|
<div class="card-footer">
|
||||||
<ul>
|
<ul>
|
||||||
<li class="hidden-sm-down">
|
<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>
|
<strong>{{ thisMonthSalesCount }}</strong>
|
||||||
</li>
|
</li>
|
||||||
<li class="hidden-sm-down">
|
<li class="hidden-sm-down">
|
||||||
|
@ -10,7 +18,7 @@
|
||||||
<strong>{{ thisMonthPurchasesTotal | currency:'GBP':'symbol':'1.2-2'}}</strong>
|
<strong>{{ thisMonthPurchasesTotal | currency:'GBP':'symbol':'1.2-2'}}</strong>
|
||||||
</li>
|
</li>
|
||||||
<li class="hidden-sm-down">
|
<li class="hidden-sm-down">
|
||||||
<div class="text-muted">Customers Today</div>
|
<div class="text-muted">Sales Today</div>
|
||||||
<strong>{{ todaySalesCount }}</strong>
|
<strong>{{ todaySalesCount }}</strong>
|
||||||
</li>
|
</li>
|
||||||
<li class="hidden-sm-down">
|
<li class="hidden-sm-down">
|
||||||
|
|
|
@ -7,6 +7,8 @@ import { OrgSnippetsService } from '../providers/org-snippets.service';
|
||||||
})
|
})
|
||||||
export class OrgBarSnippetComponent implements OnInit {
|
export class OrgBarSnippetComponent implements OnInit {
|
||||||
|
|
||||||
|
public allSalesCount = 0;
|
||||||
|
public allSalesTotal = 0;
|
||||||
public thisMonthSalesCount = 0;
|
public thisMonthSalesCount = 0;
|
||||||
public thisMonthSalesTotal = 0;
|
public thisMonthSalesTotal = 0;
|
||||||
public thisWeekSalesCount = 0;
|
public thisWeekSalesCount = 0;
|
||||||
|
@ -14,6 +16,8 @@ export class OrgBarSnippetComponent implements OnInit {
|
||||||
public todaySalesCount = 0;
|
public todaySalesCount = 0;
|
||||||
public todaySalesTotal = 0;
|
public todaySalesTotal = 0;
|
||||||
|
|
||||||
|
public allPurchasesCount = 0;
|
||||||
|
public allPurchasesTotal = 0;
|
||||||
public thisMonthPurchasesCount = 0;
|
public thisMonthPurchasesCount = 0;
|
||||||
public thisMonthPurchasesTotal = 0;
|
public thisMonthPurchasesTotal = 0;
|
||||||
public thisWeekPurchasesCount = 0;
|
public thisWeekPurchasesCount = 0;
|
||||||
|
@ -29,6 +33,8 @@ export class OrgBarSnippetComponent implements OnInit {
|
||||||
this.snippetsService.getData()
|
this.snippetsService.getData()
|
||||||
.subscribe(
|
.subscribe(
|
||||||
result => {
|
result => {
|
||||||
|
this.allSalesCount = result.snippets.all_sales_count;
|
||||||
|
this.allSalesTotal = result.snippets.all_sales_total;
|
||||||
this.thisMonthSalesCount = result.snippets.this_month_sales_count;
|
this.thisMonthSalesCount = result.snippets.this_month_sales_count;
|
||||||
this.thisMonthSalesTotal = result.snippets.this_month_sales_total;
|
this.thisMonthSalesTotal = result.snippets.this_month_sales_total;
|
||||||
this.thisWeekSalesCount = result.snippets.this_week_sales_count;
|
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.todaySalesCount = result.snippets.today_sales_count;
|
||||||
this.todaySalesTotal = result.snippets.today_sales_total;
|
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.thisMonthPurchasesCount = result.snippets.this_week_purchases_count;
|
||||||
this.thisMonthPurchasesTotal = result.snippets.this_week_purchases_total;
|
this.thisMonthPurchasesTotal = result.snippets.this_week_purchases_total;
|
||||||
this.thisWeekPurchasesCount = result.snippets.this_month_purchases_count;
|
this.thisWeekPurchasesCount = result.snippets.this_month_purchases_count;
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<div class="chart-wrapper px-3" style="height:70px;">
|
<div class="chart-wrapper px-3" style="height:70px;">
|
||||||
<canvas baseChart
|
<canvas baseChart
|
||||||
class="chart"
|
class="chart"
|
||||||
[datasets]="lineChartData"
|
[datasets]="lineGraphChartData"
|
||||||
[labels]="lineChartLabels"
|
[labels]="lineChartLabels"
|
||||||
[options]="lineChartOptions"
|
[options]="lineChartOptions"
|
||||||
[colors]="lineChartColours"
|
[colors]="lineChartColours"
|
||||||
|
|
|
@ -12,6 +12,7 @@ interface ChartData {
|
||||||
selector: 'widget-graph',
|
selector: 'widget-graph',
|
||||||
templateUrl: 'graph-widget.component.html',
|
templateUrl: 'graph-widget.component.html',
|
||||||
})
|
})
|
||||||
|
|
||||||
export class GraphWidget implements OnInit {
|
export class GraphWidget implements OnInit {
|
||||||
@Input() public graphName: string;
|
@Input() public graphName: string;
|
||||||
@Input() public graphTitle = 'Graph';
|
@Input() public graphTitle = 'Graph';
|
||||||
|
@ -24,7 +25,7 @@ export class GraphWidget implements OnInit {
|
||||||
public graphSum: Number = 0;
|
public graphSum: Number = 0;
|
||||||
public availableDataTypes = DataType;
|
public availableDataTypes = DataType;
|
||||||
|
|
||||||
public lineChartData: Array<ChartData> = [
|
public lineGraphChartData: Array<ChartData> = [
|
||||||
{
|
{
|
||||||
data: [],
|
data: [],
|
||||||
label: 'Series A'
|
label: 'Series A'
|
||||||
|
@ -35,12 +36,21 @@ export class GraphWidget implements OnInit {
|
||||||
maintainAspectRatio: false,
|
maintainAspectRatio: false,
|
||||||
scales: {
|
scales: {
|
||||||
xAxes: [{
|
xAxes: [{
|
||||||
|
type: 'time',
|
||||||
|
time: {
|
||||||
|
unit: 'day',
|
||||||
|
displayFormats: {
|
||||||
|
day: 'MMM D',
|
||||||
|
},
|
||||||
|
tooltipFormat: 'MMM D',
|
||||||
|
},
|
||||||
gridLines: {
|
gridLines: {
|
||||||
color: 'transparent',
|
color: 'transparent',
|
||||||
zeroLineColor: 'transparent'
|
zeroLineColor: 'transparent'
|
||||||
},
|
},
|
||||||
ticks: {
|
ticks: {
|
||||||
fontSize: 2,
|
fontSize: 2,
|
||||||
|
source: 'data',
|
||||||
fontColor: 'transparent',
|
fontColor: 'transparent',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +64,7 @@ export class GraphWidget implements OnInit {
|
||||||
},
|
},
|
||||||
elements: {
|
elements: {
|
||||||
line: {
|
line: {
|
||||||
borderWidth: 1
|
borderWidth: 2
|
||||||
},
|
},
|
||||||
point: {
|
point: {
|
||||||
radius: 4,
|
radius: 4,
|
||||||
|
@ -106,10 +116,16 @@ export class GraphWidget implements OnInit {
|
||||||
private setData(data: any) {
|
private setData(data: any) {
|
||||||
this.setChartData(data.data);
|
this.setChartData(data.data);
|
||||||
this.setChartLabels(data.labels);
|
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>) {
|
private setChartData(data: Array<number>) {
|
||||||
this.lineChartData[0].data = data;
|
this.lineGraphChartData[0].data = data;
|
||||||
this.graphSum = data.reduce((a, b) => a + b, 0);
|
this.graphSum = data.reduce((a, b) => a + b, 0);
|
||||||
// Set point size based on data
|
// Set point size based on data
|
||||||
if ( data.length < 15 ) {
|
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 = {
|
export const environment = {
|
||||||
production: false,
|
production: false,
|
||||||
apiUrl: 'https://dev.peartrade.org/api',
|
apiUrl: 'https://dev.localspend.co.uk/api',
|
||||||
mapApiKey: 'CHANGEME',
|
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">
|
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="app header-fixed sidebar-fixed">
|
<body class="app header-fixed sidebar-fixed">
|
||||||
<!-- Enable bootstrap 4 theme -->
|
<!-- Enable bootstrap 4 theme -->
|
||||||
<script>window.__theme = 'bs4';</script>
|
<script>window.__theme = 'bs4';</script>
|
||||||
|
@ -123,6 +122,12 @@
|
||||||
<div class="sk-cube3 sk-cube"></div>
|
<div class="sk-cube3 sk-cube"></div>
|
||||||
</div>
|
</div>
|
||||||
</app-root>
|
</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>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
|
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
|
||||||
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
|
* 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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/***************************************************************************************************
|
/***************************************************************************************************
|
||||||
|
@ -31,23 +31,37 @@ import 'core-js/es6/date';
|
||||||
import 'core-js/es6/array';
|
import 'core-js/es6/array';
|
||||||
import 'core-js/es6/regexp';
|
import 'core-js/es6/regexp';
|
||||||
import 'core-js/es6/map';
|
import 'core-js/es6/map';
|
||||||
|
import 'core-js/es6/weak-map';
|
||||||
import 'core-js/es6/set';
|
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 */
|
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
||||||
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||||
|
|
||||||
/** IE10 and IE11 requires the following to support `@angular/animation`. */
|
/** IE10 and IE11 requires the following for the Reflect API. */
|
||||||
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
|
||||||
|
|
||||||
|
|
||||||
/** Evergreen browsers require these. **/
|
|
||||||
import 'core-js/es6/reflect';
|
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%;
|
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
|
// white title font variant on type-2 as defined in _widgets.css
|
||||||
.horizontal-bars {
|
.horizontal-bars {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
@ -54,7 +73,8 @@ agm-map {
|
||||||
margin-bottom: 2px;
|
margin-bottom: 2px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.small {
|
||||||
|
}
|
||||||
&.legend {
|
&.legend {
|
||||||
text-align: center;
|
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
|
// Custom styles
|
||||||
@import "custom";
|
@import "custom";
|
||||||
|
@import "bootstrap/spinner";
|
|
@ -2,7 +2,6 @@
|
||||||
"extends": "../tsconfig.json",
|
"extends": "../tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "../out-tsc/app",
|
"outDir": "../out-tsc/app",
|
||||||
"module": "es2015",
|
|
||||||
"baseUrl": "",
|
"baseUrl": "",
|
||||||
"types": []
|
"types": []
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
"extends": "../tsconfig.json",
|
"extends": "../tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "../out-tsc/spec",
|
"outDir": "../out-tsc/spec",
|
||||||
"module": "commonjs",
|
|
||||||
"target": "es5",
|
|
||||||
"baseUrl": "",
|
"baseUrl": "",
|
||||||
"types": [
|
"types": [
|
||||||
"jasmine",
|
"jasmine",
|
||||||
|
@ -11,7 +9,8 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"test.ts"
|
"test.ts",
|
||||||
|
"polyfills.ts"
|
||||||
],
|
],
|
||||||
"include": [
|
"include": [
|
||||||
"**/*.spec.ts",
|
"**/*.spec.ts",
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
{
|
{
|
||||||
"compileOnSave": false,
|
"compileOnSave": false,
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"downlevelIteration": true,
|
||||||
|
"importHelpers": true,
|
||||||
|
"module": "esnext",
|
||||||
"outDir": "./dist/out-tsc",
|
"outDir": "./dist/out-tsc",
|
||||||
"baseUrl": "src",
|
"baseUrl": "src",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
|
@ -8,7 +11,7 @@
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"target": "es5",
|
"target": "es2015",
|
||||||
"typeRoots": [
|
"typeRoots": [
|
||||||
"node_modules/@types"
|
"node_modules/@types"
|
||||||
],
|
],
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue