Merge branch 'spencer/linting' into 'master'
Add code formatting with prettier. See merge request grassrootseconomics/cic-staff-client!17
This commit is contained in:
commit
603bafe23e
1
.husky/.gitignore
vendored
Normal file
1
.husky/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
_
|
4
.prettierignore
Normal file
4
.prettierignore
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
package.json
|
||||||
|
package-lock.json
|
||||||
|
yarn.lock
|
||||||
|
dist
|
9
.prettierrc
Normal file
9
.prettierrc
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"useTabs": false,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"singleQuote": true,
|
||||||
|
"printWidth": 100,
|
||||||
|
"semi": true,
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"arrowParens": "always"
|
||||||
|
}
|
634
package-lock.json
generated
634
package-lock.json
generated
@ -57,6 +57,7 @@
|
|||||||
"@types/node": "^12.20.6",
|
"@types/node": "^12.20.6",
|
||||||
"codelyzer": "^6.0.0",
|
"codelyzer": "^6.0.0",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
|
"husky": "^6.0.0",
|
||||||
"jasmine-core": "~3.6.0",
|
"jasmine-core": "~3.6.0",
|
||||||
"jasmine-spec-reporter": "~5.0.0",
|
"jasmine-spec-reporter": "~5.0.0",
|
||||||
"karma": "~5.0.0",
|
"karma": "~5.0.0",
|
||||||
@ -65,10 +66,15 @@
|
|||||||
"karma-jasmine": "~4.0.0",
|
"karma-jasmine": "~4.0.0",
|
||||||
"karma-jasmine-html-reporter": "^1.5.0",
|
"karma-jasmine-html-reporter": "^1.5.0",
|
||||||
"karma-junit-reporter": "^2.0.1",
|
"karma-junit-reporter": "^2.0.1",
|
||||||
|
"prettier": "^2.3.0",
|
||||||
|
"pretty-quick": "^3.1.0",
|
||||||
"protractor": "~7.0.0",
|
"protractor": "~7.0.0",
|
||||||
"secp256k1": "^4.0.2",
|
"secp256k1": "^4.0.2",
|
||||||
"ts-node": "~8.3.0",
|
"ts-node": "~8.3.0",
|
||||||
"tslint": "~6.1.0",
|
"tslint": "~6.1.0",
|
||||||
|
"tslint-angular": "^3.0.3",
|
||||||
|
"tslint-config-prettier": "^1.18.0",
|
||||||
|
"tslint-jasmine-rules": "^1.6.1",
|
||||||
"typescript": "~4.0.2",
|
"typescript": "~4.0.2",
|
||||||
"yargs": "^13.3.2"
|
"yargs": "^13.3.2"
|
||||||
}
|
}
|
||||||
@ -3810,6 +3816,15 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/array-differ": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/array-filter": {
|
"node_modules/array-filter": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz",
|
||||||
@ -9284,6 +9299,15 @@
|
|||||||
"ms": "^2.1.1"
|
"ms": "^2.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/human-signals": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/humanize-ms": {
|
"node_modules/humanize-ms": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
|
||||||
@ -9292,6 +9316,18 @@
|
|||||||
"ms": "^2.0.0"
|
"ms": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/husky": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/husky/-/husky-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-SQS2gDTB7tBN486QSoKPKQItZw97BMOd+Kdb6ghfpBc0yXyzrddI0oDV5MkDAbuB4X2mO3/nj60TRMcYxwzZeQ==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"husky": "lib/bin.js"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/typicode"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/iconv-lite": {
|
"node_modules/iconv-lite": {
|
||||||
"version": "0.6.2",
|
"version": "0.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz",
|
||||||
@ -12375,6 +12411,15 @@
|
|||||||
"rimraf": "bin.js"
|
"rimraf": "bin.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mri": {
|
||||||
|
"version": "1.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/mri/-/mri-1.1.6.tgz",
|
||||||
|
"integrity": "sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
@ -12453,6 +12498,31 @@
|
|||||||
"buffer": "^5.5.0"
|
"buffer": "^5.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/multimatch": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/multimatch/-/multimatch-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/minimatch": "^3.0.3",
|
||||||
|
"array-differ": "^3.0.0",
|
||||||
|
"array-union": "^2.1.0",
|
||||||
|
"arrify": "^2.0.1",
|
||||||
|
"minimatch": "^3.0.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/multimatch/node_modules/arrify": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mute-stream": {
|
"node_modules/mute-stream": {
|
||||||
"version": "0.0.8",
|
"version": "0.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
|
||||||
@ -14886,6 +14956,272 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prettier": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"prettier": "bin-prettier.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.13.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pretty-quick": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-DtxIxksaUWCgPFN7E1ZZk4+Aav3CCuRdhrDSFZENb404sYMtuo9Zka823F+Mgeyt8Zt3bUiCjFzzWYE9LYqkmQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"chalk": "^3.0.0",
|
||||||
|
"execa": "^4.0.0",
|
||||||
|
"find-up": "^4.1.0",
|
||||||
|
"ignore": "^5.1.4",
|
||||||
|
"mri": "^1.1.5",
|
||||||
|
"multimatch": "^4.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"pretty-quick": "bin/pretty-quick.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.13"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"prettier": ">=2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pretty-quick/node_modules/ansi-styles": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"color-convert": "^2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pretty-quick/node_modules/chalk": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": "^4.1.0",
|
||||||
|
"supports-color": "^7.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pretty-quick/node_modules/color-convert": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"color-name": "~1.1.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pretty-quick/node_modules/color-name": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/pretty-quick/node_modules/cross-spawn": {
|
||||||
|
"version": "7.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||||
|
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"path-key": "^3.1.0",
|
||||||
|
"shebang-command": "^2.0.0",
|
||||||
|
"which": "^2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pretty-quick/node_modules/execa": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"cross-spawn": "^7.0.0",
|
||||||
|
"get-stream": "^5.0.0",
|
||||||
|
"human-signals": "^1.1.1",
|
||||||
|
"is-stream": "^2.0.0",
|
||||||
|
"merge-stream": "^2.0.0",
|
||||||
|
"npm-run-path": "^4.0.0",
|
||||||
|
"onetime": "^5.1.0",
|
||||||
|
"signal-exit": "^3.0.2",
|
||||||
|
"strip-final-newline": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sindresorhus/execa?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pretty-quick/node_modules/find-up": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"locate-path": "^5.0.0",
|
||||||
|
"path-exists": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pretty-quick/node_modules/get-stream": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"pump": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pretty-quick/node_modules/has-flag": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pretty-quick/node_modules/is-stream": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pretty-quick/node_modules/locate-path": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"p-locate": "^4.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pretty-quick/node_modules/npm-run-path": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"path-key": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pretty-quick/node_modules/p-locate": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"p-limit": "^2.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pretty-quick/node_modules/path-exists": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pretty-quick/node_modules/path-key": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pretty-quick/node_modules/shebang-command": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"shebang-regex": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pretty-quick/node_modules/shebang-regex": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pretty-quick/node_modules/supports-color": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"has-flag": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pretty-quick/node_modules/which": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"isexe": "^2.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"node-which": "bin/node-which"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/printj": {
|
"node_modules/printj": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz",
|
||||||
@ -17549,6 +17885,15 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/strip-final-newline": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/strip-hex-prefix": {
|
"node_modules/strip-hex-prefix": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz",
|
||||||
@ -18236,6 +18581,37 @@
|
|||||||
"node": ">=4.8.0"
|
"node": ">=4.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tslint-angular": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslint-angular/-/tslint-angular-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-5xD1gLE89lBExfSbMslDw/ZfOZM0t0CJsoJa4svsgF7tlwVS3IpXjzNcNRN0RZqDBj+cdTlbeel6GpZ3PqpPiw==",
|
||||||
|
"dev": true,
|
||||||
|
"peerDependencies": {
|
||||||
|
"codelyzer": ">=5.0.0",
|
||||||
|
"tslint": ">=5.16.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tslint-config-prettier": {
|
||||||
|
"version": "1.18.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz",
|
||||||
|
"integrity": "sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"tslint-config-prettier-check": "bin/check.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tslint-jasmine-rules": {
|
||||||
|
"version": "1.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslint-jasmine-rules/-/tslint-jasmine-rules-1.6.1.tgz",
|
||||||
|
"integrity": "sha512-XH5Op9yJQvzySlb79/JO/GQWDMzC+F6zNC7ay1LW9WDYpVmbxhGyefauT5zg3uGkMh1CN35UE2CGbsVOO1bnDw==",
|
||||||
|
"dev": true,
|
||||||
|
"peerDependencies": {
|
||||||
|
"tslint": ">=5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tslint/node_modules/semver": {
|
"node_modules/tslint/node_modules/semver": {
|
||||||
"version": "5.7.1",
|
"version": "5.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||||
@ -24084,6 +24460,12 @@
|
|||||||
"integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
|
"integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"array-differ": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"array-filter": {
|
"array-filter": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz",
|
||||||
@ -28794,6 +29176,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"human-signals": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"humanize-ms": {
|
"humanize-ms": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
|
||||||
@ -28802,6 +29190,12 @@
|
|||||||
"ms": "^2.0.0"
|
"ms": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"husky": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/husky/-/husky-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-SQS2gDTB7tBN486QSoKPKQItZw97BMOd+Kdb6ghfpBc0yXyzrddI0oDV5MkDAbuB4X2mO3/nj60TRMcYxwzZeQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"iconv-lite": {
|
"iconv-lite": {
|
||||||
"version": "0.6.2",
|
"version": "0.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz",
|
||||||
@ -31251,6 +31645,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mri": {
|
||||||
|
"version": "1.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/mri/-/mri-1.1.6.tgz",
|
||||||
|
"integrity": "sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"ms": {
|
"ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
@ -31330,6 +31730,27 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"multimatch": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/multimatch/-/multimatch-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/minimatch": "^3.0.3",
|
||||||
|
"array-differ": "^3.0.0",
|
||||||
|
"array-union": "^2.1.0",
|
||||||
|
"arrify": "^2.0.1",
|
||||||
|
"minimatch": "^3.0.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"arrify": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"mute-stream": {
|
"mute-stream": {
|
||||||
"version": "0.0.8",
|
"version": "0.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
|
||||||
@ -33413,6 +33834,193 @@
|
|||||||
"resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
|
||||||
"integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw="
|
"integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw="
|
||||||
},
|
},
|
||||||
|
"prettier": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"pretty-quick": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-DtxIxksaUWCgPFN7E1ZZk4+Aav3CCuRdhrDSFZENb404sYMtuo9Zka823F+Mgeyt8Zt3bUiCjFzzWYE9LYqkmQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"chalk": "^3.0.0",
|
||||||
|
"execa": "^4.0.0",
|
||||||
|
"find-up": "^4.1.0",
|
||||||
|
"ignore": "^5.1.4",
|
||||||
|
"mri": "^1.1.5",
|
||||||
|
"multimatch": "^4.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"color-convert": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"chalk": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-styles": "^4.1.0",
|
||||||
|
"supports-color": "^7.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"color-convert": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"color-name": "~1.1.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"color-name": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"cross-spawn": {
|
||||||
|
"version": "7.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||||
|
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"path-key": "^3.1.0",
|
||||||
|
"shebang-command": "^2.0.0",
|
||||||
|
"which": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"execa": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"cross-spawn": "^7.0.0",
|
||||||
|
"get-stream": "^5.0.0",
|
||||||
|
"human-signals": "^1.1.1",
|
||||||
|
"is-stream": "^2.0.0",
|
||||||
|
"merge-stream": "^2.0.0",
|
||||||
|
"npm-run-path": "^4.0.0",
|
||||||
|
"onetime": "^5.1.0",
|
||||||
|
"signal-exit": "^3.0.2",
|
||||||
|
"strip-final-newline": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"find-up": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"locate-path": "^5.0.0",
|
||||||
|
"path-exists": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"get-stream": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"pump": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"has-flag": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"is-stream": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"locate-path": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"p-locate": "^4.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"npm-run-path": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"path-key": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"p-locate": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"p-limit": "^2.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"path-exists": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"path-key": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"shebang-command": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"shebang-regex": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"shebang-regex": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"supports-color": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"has-flag": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"which": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"isexe": "^2.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"printj": {
|
"printj": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz",
|
||||||
@ -35686,6 +36294,12 @@
|
|||||||
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
|
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"strip-final-newline": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"strip-hex-prefix": {
|
"strip-hex-prefix": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz",
|
||||||
@ -36252,6 +36866,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"tslint-angular": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslint-angular/-/tslint-angular-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-5xD1gLE89lBExfSbMslDw/ZfOZM0t0CJsoJa4svsgF7tlwVS3IpXjzNcNRN0RZqDBj+cdTlbeel6GpZ3PqpPiw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
|
"tslint-config-prettier": {
|
||||||
|
"version": "1.18.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz",
|
||||||
|
"integrity": "sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"tslint-jasmine-rules": {
|
||||||
|
"version": "1.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslint-jasmine-rules/-/tslint-jasmine-rules-1.6.1.tgz",
|
||||||
|
"integrity": "sha512-XH5Op9yJQvzySlb79/JO/GQWDMzC+F6zNC7ay1LW9WDYpVmbxhGyefauT5zg3uGkMh1CN35UE2CGbsVOO1bnDw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"tsutils": {
|
"tsutils": {
|
||||||
"version": "2.29.0",
|
"version": "2.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
|
||||||
|
18
package.json
18
package.json
@ -10,9 +10,14 @@
|
|||||||
"build:prod": "ng build --prod",
|
"build:prod": "ng build --prod",
|
||||||
"start:pwa": "npm run build:prod && http-server -p 4200 dist/cic-staff-client",
|
"start:pwa": "npm run build:prod && http-server -p 4200 dist/cic-staff-client",
|
||||||
"test:dev": "ng test",
|
"test:dev": "ng test",
|
||||||
|
"format:check": "prettier --config ./.prettierrc --list-different \"src/{app,environments,assets}/**/*.{ts,js,json,css,scss}\"",
|
||||||
|
"format:refactor": "prettier --config ./.prettierrc --write \"src/{app,environments,assets}/**/*.{ts,js,json,css,scss}\"",
|
||||||
|
"format:fix": "pretty-quick --staged",
|
||||||
"lint": "ng lint",
|
"lint": "ng lint",
|
||||||
"e2e": "ng e2e",
|
"e2e": "ng e2e",
|
||||||
"postinstall": "node patch-webpack.js"
|
"precommit": "format:fix && lint",
|
||||||
|
"postinstall": "node patch-webpack.js",
|
||||||
|
"prepare": "husky install"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -65,6 +70,7 @@
|
|||||||
"@types/node": "^12.20.6",
|
"@types/node": "^12.20.6",
|
||||||
"codelyzer": "^6.0.0",
|
"codelyzer": "^6.0.0",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
|
"husky": "^6.0.0",
|
||||||
"jasmine-core": "~3.6.0",
|
"jasmine-core": "~3.6.0",
|
||||||
"jasmine-spec-reporter": "~5.0.0",
|
"jasmine-spec-reporter": "~5.0.0",
|
||||||
"karma": "~5.0.0",
|
"karma": "~5.0.0",
|
||||||
@ -73,11 +79,21 @@
|
|||||||
"karma-jasmine": "~4.0.0",
|
"karma-jasmine": "~4.0.0",
|
||||||
"karma-jasmine-html-reporter": "^1.5.0",
|
"karma-jasmine-html-reporter": "^1.5.0",
|
||||||
"karma-junit-reporter": "^2.0.1",
|
"karma-junit-reporter": "^2.0.1",
|
||||||
|
"prettier": "^2.3.0",
|
||||||
|
"pretty-quick": "^3.1.0",
|
||||||
"protractor": "~7.0.0",
|
"protractor": "~7.0.0",
|
||||||
"secp256k1": "^4.0.2",
|
"secp256k1": "^4.0.2",
|
||||||
"ts-node": "~8.3.0",
|
"ts-node": "~8.3.0",
|
||||||
"tslint": "~6.1.0",
|
"tslint": "~6.1.0",
|
||||||
|
"tslint-angular": "^3.0.3",
|
||||||
|
"tslint-config-prettier": "^1.18.0",
|
||||||
|
"tslint-jasmine-rules": "^1.6.1",
|
||||||
"typescript": "~4.0.2",
|
"typescript": "~4.0.2",
|
||||||
"yargs": "^13.3.2"
|
"yargs": "^13.3.2"
|
||||||
|
},
|
||||||
|
"husky": {
|
||||||
|
"hooks": {
|
||||||
|
"pre-commit": "pretty-quick --staged & ng lint"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ export class AccountIndex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async haveAccount(address: string): Promise<boolean> {
|
public async haveAccount(address: string): Promise<boolean> {
|
||||||
return await this.contract.methods.accountIndex(address).call() !== 0;
|
return (await this.contract.methods.accountIndex(address).call()) !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async last(numberOfAccounts: number): Promise<Array<string>> {
|
public async last(numberOfAccounts: number): Promise<Array<string>> {
|
||||||
@ -42,7 +42,7 @@ export class AccountIndex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async addToAccountRegistry(address: string): Promise<boolean> {
|
public async addToAccountRegistry(address: string): Promise<boolean> {
|
||||||
if (!await this.haveAccount(address)) {
|
if (!(await this.haveAccount(address))) {
|
||||||
return await this.contract.methods.add(address).send({ from: this.signerAddress });
|
return await this.contract.methods.add(address).send({ from: this.signerAddress });
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1,22 +1,27 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router} from '@angular/router';
|
import {
|
||||||
|
CanActivate,
|
||||||
|
ActivatedRouteSnapshot,
|
||||||
|
RouterStateSnapshot,
|
||||||
|
UrlTree,
|
||||||
|
Router,
|
||||||
|
} from '@angular/router';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class AuthGuard implements CanActivate {
|
export class AuthGuard implements CanActivate {
|
||||||
|
|
||||||
constructor(private router: Router) {}
|
constructor(private router: Router) {}
|
||||||
|
|
||||||
canActivate(
|
canActivate(
|
||||||
route: ActivatedRouteSnapshot,
|
route: ActivatedRouteSnapshot,
|
||||||
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
|
state: RouterStateSnapshot
|
||||||
|
): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
|
||||||
if (localStorage.getItem(btoa('CICADA_PRIVATE_KEY'))) {
|
if (localStorage.getItem(btoa('CICADA_PRIVATE_KEY'))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
this.router.navigate(['/auth']);
|
this.router.navigate(['/auth']);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,23 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router} from '@angular/router';
|
import {
|
||||||
|
CanActivate,
|
||||||
|
ActivatedRouteSnapshot,
|
||||||
|
RouterStateSnapshot,
|
||||||
|
UrlTree,
|
||||||
|
Router,
|
||||||
|
} from '@angular/router';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class RoleGuard implements CanActivate {
|
export class RoleGuard implements CanActivate {
|
||||||
|
|
||||||
constructor(private router: Router) {}
|
constructor(private router: Router) {}
|
||||||
|
|
||||||
canActivate(
|
canActivate(
|
||||||
route: ActivatedRouteSnapshot,
|
route: ActivatedRouteSnapshot,
|
||||||
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
|
state: RouterStateSnapshot
|
||||||
|
): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
|
||||||
const currentUser = JSON.parse(localStorage.getItem(atob('CICADA_USER')));
|
const currentUser = JSON.parse(localStorage.getItem(atob('CICADA_USER')));
|
||||||
if (currentUser) {
|
if (currentUser) {
|
||||||
if (route.data.roles && route.data.roles.indexOf(currentUser.role) === -1) {
|
if (route.data.roles && route.data.roles.indexOf(currentUser.role) === -1) {
|
||||||
@ -24,5 +30,4 @@ export class RoleGuard implements CanActivate {
|
|||||||
this.router.navigate(['/auth'], { queryParams: { returnUrl: state.url } });
|
this.router.navigate(['/auth'], { queryParams: { returnUrl: state.url } });
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,4 @@ function arraySum(arr: Array<number>): number {
|
|||||||
return arr.reduce((accumulator, current) => accumulator + current, 0);
|
return arr.reduce((accumulator, current) => accumulator + current, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export { arraySum };
|
||||||
arraySum
|
|
||||||
};
|
|
||||||
|
@ -32,7 +32,7 @@ function copyToClipboard(text: any): boolean {
|
|||||||
// copy the text
|
// copy the text
|
||||||
document.execCommand('copy');
|
document.execCommand('copy');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
window.alert('Your Browser Doesn\'t support this! Error : ' + err);
|
window.alert('Your Browser Does not support this! Error : ' + err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// remove the selection range (Chrome throws a warning if we don't.)
|
// remove the selection range (Chrome throws a warning if we don't.)
|
||||||
@ -48,6 +48,4 @@ function copyToClipboard(text: any): boolean {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export { copyToClipboard };
|
||||||
copyToClipboard
|
|
||||||
};
|
|
||||||
|
@ -4,7 +4,7 @@ function exportCsv(arrayData: Array<any>, filename: string, delimiter: string =
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let csv: string = Object.keys(arrayData[0]).join(delimiter) + '\n';
|
let csv: string = Object.keys(arrayData[0]).join(delimiter) + '\n';
|
||||||
arrayData.forEach(obj => {
|
arrayData.forEach((obj) => {
|
||||||
const row: Array<any> = [];
|
const row: Array<any> = [];
|
||||||
for (const key in obj) {
|
for (const key in obj) {
|
||||||
if (obj.hasOwnProperty(key)) {
|
if (obj.hasOwnProperty(key)) {
|
||||||
@ -33,6 +33,4 @@ function removeSpecialChar(str: string): string {
|
|||||||
return str.replace(/[^a-zA-Z0-9 ]/g, '');
|
return str.replace(/[^a-zA-Z0-9 ]/g, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export { exportCsv };
|
||||||
exportCsv
|
|
||||||
};
|
|
||||||
|
@ -17,10 +17,7 @@ export class HttpError extends Error {
|
|||||||
export class GlobalErrorHandler extends ErrorHandler {
|
export class GlobalErrorHandler extends ErrorHandler {
|
||||||
private sentencesForWarningLogging: Array<string> = [];
|
private sentencesForWarningLogging: Array<string> = [];
|
||||||
|
|
||||||
constructor(
|
constructor(private loggingService: LoggingService, private router: Router) {
|
||||||
private loggingService: LoggingService,
|
|
||||||
private router: Router
|
|
||||||
) {
|
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,14 +45,30 @@ export class GlobalErrorHandler extends ErrorHandler {
|
|||||||
const route: string = this.router.url;
|
const route: string = this.router.url;
|
||||||
if (error instanceof HttpErrorResponse) {
|
if (error instanceof HttpErrorResponse) {
|
||||||
this.loggingService.sendErrorLevelMessage(
|
this.loggingService.sendErrorLevelMessage(
|
||||||
`There was an HTTP error on route ${route}.\n${error.message}.\nStatus code: ${(error as HttpErrorResponse).status}`,
|
`There was an HTTP error on route ${route}.\n${error.message}.\nStatus code: ${
|
||||||
this, {error});
|
(error as HttpErrorResponse).status
|
||||||
|
}`,
|
||||||
|
this,
|
||||||
|
{ error }
|
||||||
|
);
|
||||||
} else if (error instanceof TypeError) {
|
} else if (error instanceof TypeError) {
|
||||||
this.loggingService.sendErrorLevelMessage(`There was a Type error on route ${route}.\n${error.message}`, this, {error});
|
this.loggingService.sendErrorLevelMessage(
|
||||||
|
`There was a Type error on route ${route}.\n${error.message}`,
|
||||||
|
this,
|
||||||
|
{ error }
|
||||||
|
);
|
||||||
} else if (error instanceof Error) {
|
} else if (error instanceof Error) {
|
||||||
this.loggingService.sendErrorLevelMessage(`There was a general error on route ${route}.\n${error.message}`, this, {error});
|
this.loggingService.sendErrorLevelMessage(
|
||||||
|
`There was a general error on route ${route}.\n${error.message}`,
|
||||||
|
this,
|
||||||
|
{ error }
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
this.loggingService.sendErrorLevelMessage(`Nobody threw an error but something happened on route ${route}!`, this, {error});
|
this.loggingService.sendErrorLevelMessage(
|
||||||
|
`Nobody threw an error but something happened on route ${route}!`,
|
||||||
|
this,
|
||||||
|
{ error }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
function HttpGetter(): void {}
|
function HttpGetter(): void {}
|
||||||
|
|
||||||
HttpGetter.prototype.get = filename => new Promise((resolve, reject) => {
|
HttpGetter.prototype.get = (filename) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
const xhr: XMLHttpRequest = new XMLHttpRequest();
|
const xhr: XMLHttpRequest = new XMLHttpRequest();
|
||||||
xhr.addEventListener('load', (e) => {
|
xhr.addEventListener('load', (e) => {
|
||||||
if (xhr.status === 200) {
|
if (xhr.status === 200) {
|
||||||
@ -13,6 +14,4 @@ HttpGetter.prototype.get = filename => new Promise((resolve, reject) => {
|
|||||||
xhr.send();
|
xhr.send();
|
||||||
});
|
});
|
||||||
|
|
||||||
export {
|
export { HttpGetter };
|
||||||
HttpGetter
|
|
||||||
};
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,13 @@
|
|||||||
const objCsv: { size: number, dataFile: any } = {
|
const objCsv: { size: number; dataFile: any } = {
|
||||||
size: 0,
|
size: 0,
|
||||||
dataFile: []
|
dataFile: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
function readCsv(input: any): Array<any> | void {
|
function readCsv(input: any): Array<any> | void {
|
||||||
if (input.files && input.files[0]) {
|
if (input.files && input.files[0]) {
|
||||||
const reader: FileReader = new FileReader();
|
const reader: FileReader = new FileReader();
|
||||||
reader.readAsBinaryString(input.files[0]);
|
reader.readAsBinaryString(input.files[0]);
|
||||||
reader.onload = event => {
|
reader.onload = (event) => {
|
||||||
objCsv.size = event.total;
|
objCsv.size = event.total;
|
||||||
objCsv.dataFile = event.target.result;
|
objCsv.dataFile = event.target.result;
|
||||||
return parseData(objCsv.dataFile);
|
return parseData(objCsv.dataFile);
|
||||||
@ -18,13 +18,11 @@ function readCsv(input: any): Array<any> | void {
|
|||||||
function parseData(data: any): Array<any> {
|
function parseData(data: any): Array<any> {
|
||||||
const csvData: Array<any> = [];
|
const csvData: Array<any> = [];
|
||||||
const lineBreak: Array<any> = data.split('\n');
|
const lineBreak: Array<any> = data.split('\n');
|
||||||
lineBreak.forEach(res => {
|
lineBreak.forEach((res) => {
|
||||||
csvData.push(res.split(','));
|
csvData.push(res.split(','));
|
||||||
});
|
});
|
||||||
console.table(csvData);
|
console.table(csvData);
|
||||||
return csvData;
|
return csvData;
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export { readCsv };
|
||||||
readCsv
|
|
||||||
};
|
|
||||||
|
@ -4,7 +4,7 @@ async function personValidation(person: any): Promise<void> {
|
|||||||
const personValidationErrors: any = await validatePerson(person);
|
const personValidationErrors: any = await validatePerson(person);
|
||||||
|
|
||||||
if (personValidationErrors) {
|
if (personValidationErrors) {
|
||||||
personValidationErrors.map(error => console.error(`${error.message}`));
|
personValidationErrors.map((error) => console.error(`${error.message}`));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12,11 +12,8 @@ async function vcardValidation(vcard: any): Promise<void> {
|
|||||||
const vcardValidationErrors: any = await validateVcard(vcard);
|
const vcardValidationErrors: any = await validateVcard(vcard);
|
||||||
|
|
||||||
if (vcardValidationErrors) {
|
if (vcardValidationErrors) {
|
||||||
vcardValidationErrors.map(error => console.error(`${error.message}`));
|
vcardValidationErrors.map((error) => console.error(`${error.message}`));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export { personValidation, vcardValidation };
|
||||||
personValidation,
|
|
||||||
vcardValidation,
|
|
||||||
};
|
|
||||||
|
@ -3,11 +3,11 @@ import { TestBed } from '@angular/core/testing';
|
|||||||
import { ErrorInterceptor } from '@app/_interceptors/error.interceptor';
|
import { ErrorInterceptor } from '@app/_interceptors/error.interceptor';
|
||||||
|
|
||||||
describe('ErrorInterceptor', () => {
|
describe('ErrorInterceptor', () => {
|
||||||
beforeEach(() => TestBed.configureTestingModule({
|
beforeEach(() =>
|
||||||
providers: [
|
TestBed.configureTestingModule({
|
||||||
ErrorInterceptor
|
providers: [ErrorInterceptor],
|
||||||
]
|
})
|
||||||
}));
|
);
|
||||||
|
|
||||||
it('should be created', () => {
|
it('should be created', () => {
|
||||||
const interceptor: ErrorInterceptor = TestBed.inject(ErrorInterceptor);
|
const interceptor: ErrorInterceptor = TestBed.inject(ErrorInterceptor);
|
||||||
|
@ -3,7 +3,8 @@ import {
|
|||||||
HttpRequest,
|
HttpRequest,
|
||||||
HttpHandler,
|
HttpHandler,
|
||||||
HttpEvent,
|
HttpEvent,
|
||||||
HttpInterceptor, HttpErrorResponse
|
HttpInterceptor,
|
||||||
|
HttpErrorResponse,
|
||||||
} from '@angular/common/http';
|
} from '@angular/common/http';
|
||||||
import { Observable, throwError } from 'rxjs';
|
import { Observable, throwError } from 'rxjs';
|
||||||
import { catchError } from 'rxjs/operators';
|
import { catchError } from 'rxjs/operators';
|
||||||
@ -12,7 +13,6 @@ import {Router} from '@angular/router';
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ErrorInterceptor implements HttpInterceptor {
|
export class ErrorInterceptor implements HttpInterceptor {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private errorDialogService: ErrorDialogService,
|
private errorDialogService: ErrorDialogService,
|
||||||
private loggingService: LoggingService,
|
private loggingService: LoggingService,
|
||||||
@ -29,7 +29,9 @@ export class ErrorInterceptor implements HttpInterceptor {
|
|||||||
} else {
|
} else {
|
||||||
// The backend returned an unsuccessful response code.
|
// The backend returned an unsuccessful response code.
|
||||||
// The response body may contain clues as to what went wrong.
|
// The response body may contain clues as to what went wrong.
|
||||||
errorMessage = `Backend returned code ${err.status}, body was: ${JSON.stringify(err.error)}`;
|
errorMessage = `Backend returned code ${err.status}, body was: ${JSON.stringify(
|
||||||
|
err.error
|
||||||
|
)}`;
|
||||||
}
|
}
|
||||||
this.loggingService.sendErrorLevelMessage(errorMessage, this, { error: err });
|
this.loggingService.sendErrorLevelMessage(errorMessage, this, { error: err });
|
||||||
switch (err.status) {
|
switch (err.status) {
|
||||||
|
@ -3,11 +3,11 @@ import { TestBed } from '@angular/core/testing';
|
|||||||
import { HttpConfigInterceptor } from './http-config.interceptor';
|
import { HttpConfigInterceptor } from './http-config.interceptor';
|
||||||
|
|
||||||
describe('HttpConfigInterceptor', () => {
|
describe('HttpConfigInterceptor', () => {
|
||||||
beforeEach(() => TestBed.configureTestingModule({
|
beforeEach(() =>
|
||||||
providers: [
|
TestBed.configureTestingModule({
|
||||||
HttpConfigInterceptor
|
providers: [HttpConfigInterceptor],
|
||||||
]
|
})
|
||||||
}));
|
);
|
||||||
|
|
||||||
it('should be created', () => {
|
it('should be created', () => {
|
||||||
const interceptor: HttpConfigInterceptor = TestBed.inject(HttpConfigInterceptor);
|
const interceptor: HttpConfigInterceptor = TestBed.inject(HttpConfigInterceptor);
|
||||||
|
@ -1,15 +1,9 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import {
|
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
|
||||||
HttpRequest,
|
|
||||||
HttpHandler,
|
|
||||||
HttpEvent,
|
|
||||||
HttpInterceptor
|
|
||||||
} from '@angular/common/http';
|
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class HttpConfigInterceptor implements HttpInterceptor {
|
export class HttpConfigInterceptor implements HttpInterceptor {
|
||||||
|
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
|
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
|
||||||
|
@ -3,11 +3,11 @@ import { TestBed } from '@angular/core/testing';
|
|||||||
import { LoggingInterceptor } from './logging.interceptor';
|
import { LoggingInterceptor } from './logging.interceptor';
|
||||||
|
|
||||||
describe('LoggingInterceptor', () => {
|
describe('LoggingInterceptor', () => {
|
||||||
beforeEach(() => TestBed.configureTestingModule({
|
beforeEach(() =>
|
||||||
providers: [
|
TestBed.configureTestingModule({
|
||||||
LoggingInterceptor
|
providers: [LoggingInterceptor],
|
||||||
]
|
})
|
||||||
}));
|
);
|
||||||
|
|
||||||
it('should be created', () => {
|
it('should be created', () => {
|
||||||
const interceptor: LoggingInterceptor = TestBed.inject(LoggingInterceptor);
|
const interceptor: LoggingInterceptor = TestBed.inject(LoggingInterceptor);
|
||||||
|
@ -4,7 +4,7 @@ import {
|
|||||||
HttpHandler,
|
HttpHandler,
|
||||||
HttpEvent,
|
HttpEvent,
|
||||||
HttpInterceptor,
|
HttpInterceptor,
|
||||||
HttpResponse
|
HttpResponse,
|
||||||
} from '@angular/common/http';
|
} from '@angular/common/http';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { LoggingService } from '@app/_services/logging.service';
|
import { LoggingService } from '@app/_services/logging.service';
|
||||||
@ -12,10 +12,7 @@ import {finalize, tap} from 'rxjs/operators';
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class LoggingInterceptor implements HttpInterceptor {
|
export class LoggingInterceptor implements HttpInterceptor {
|
||||||
|
constructor(private loggingService: LoggingService) {}
|
||||||
constructor(
|
|
||||||
private loggingService: LoggingService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
|
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
|
||||||
return next.handle(request);
|
return next.handle(request);
|
||||||
|
@ -20,24 +20,34 @@ interface AccountDetails {
|
|||||||
products: string[];
|
products: string[];
|
||||||
category?: string;
|
category?: string;
|
||||||
vcard: {
|
vcard: {
|
||||||
email: [{
|
email: [
|
||||||
|
{
|
||||||
value: string;
|
value: string;
|
||||||
}];
|
}
|
||||||
fn: [{
|
];
|
||||||
|
fn: [
|
||||||
|
{
|
||||||
value: string;
|
value: string;
|
||||||
}];
|
}
|
||||||
n: [{
|
];
|
||||||
|
n: [
|
||||||
|
{
|
||||||
value: string[];
|
value: string[];
|
||||||
}];
|
}
|
||||||
tel: [{
|
];
|
||||||
|
tel: [
|
||||||
|
{
|
||||||
meta: {
|
meta: {
|
||||||
TYP: string[];
|
TYP: string[];
|
||||||
},
|
};
|
||||||
value: string;
|
value: string;
|
||||||
}],
|
}
|
||||||
version: [{
|
];
|
||||||
|
version: [
|
||||||
|
{
|
||||||
value: string;
|
value: string;
|
||||||
}];
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,31 +85,35 @@ const defaultAccount: AccountDetails = {
|
|||||||
},
|
},
|
||||||
products: [],
|
products: [],
|
||||||
vcard: {
|
vcard: {
|
||||||
email: [{
|
email: [
|
||||||
|
{
|
||||||
value: '',
|
value: '',
|
||||||
}],
|
},
|
||||||
fn: [{
|
],
|
||||||
|
fn: [
|
||||||
|
{
|
||||||
value: 'Sarafu Contract',
|
value: 'Sarafu Contract',
|
||||||
}],
|
},
|
||||||
n: [{
|
],
|
||||||
|
n: [
|
||||||
|
{
|
||||||
value: ['Sarafu', 'Contract'],
|
value: ['Sarafu', 'Contract'],
|
||||||
}],
|
},
|
||||||
tel: [{
|
],
|
||||||
|
tel: [
|
||||||
|
{
|
||||||
meta: {
|
meta: {
|
||||||
TYP: [],
|
TYP: [],
|
||||||
},
|
},
|
||||||
value: '',
|
value: '',
|
||||||
}],
|
},
|
||||||
version: [{
|
],
|
||||||
|
version: [
|
||||||
|
{
|
||||||
value: '3.0',
|
value: '3.0',
|
||||||
}],
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export {
|
export { AccountDetails, Signature, Meta, MetaResponse, defaultAccount };
|
||||||
AccountDetails,
|
|
||||||
Signature,
|
|
||||||
Meta,
|
|
||||||
MetaResponse,
|
|
||||||
defaultAccount
|
|
||||||
};
|
|
||||||
|
@ -21,9 +21,4 @@ interface AreaType {
|
|||||||
area: Array<string>;
|
area: Array<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export { Action, Category, AreaName, AreaType };
|
||||||
Action,
|
|
||||||
Category,
|
|
||||||
AreaName,
|
|
||||||
AreaType
|
|
||||||
};
|
|
||||||
|
@ -17,7 +17,4 @@ class W3 {
|
|||||||
provider: any;
|
provider: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export { Settings, W3 };
|
||||||
Settings,
|
|
||||||
W3
|
|
||||||
};
|
|
||||||
|
@ -6,6 +6,4 @@ interface Staff {
|
|||||||
userid: string;
|
userid: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export { Staff };
|
||||||
Staff
|
|
||||||
};
|
|
||||||
|
@ -8,12 +8,10 @@ interface Token {
|
|||||||
'0xa686005CE37Dce7738436256982C3903f2E4ea8E'?: {
|
'0xa686005CE37Dce7738436256982C3903f2E4ea8E'?: {
|
||||||
weight: string;
|
weight: string;
|
||||||
balance: string;
|
balance: string;
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
reserveRatio?: string;
|
reserveRatio?: string;
|
||||||
owner?: string;
|
owner?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export { Token };
|
||||||
Token
|
|
||||||
};
|
|
||||||
|
@ -43,10 +43,4 @@ class Conversion {
|
|||||||
tx: Tx;
|
tx: Tx;
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export { BlocksBloom, TxToken, Tx, Transaction, Conversion };
|
||||||
BlocksBloom,
|
|
||||||
TxToken,
|
|
||||||
Tx,
|
|
||||||
Transaction,
|
|
||||||
Conversion
|
|
||||||
};
|
|
||||||
|
@ -32,7 +32,6 @@ interface MutableKeyStore extends KeyStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MutablePgpKeyStore implements MutableKeyStore {
|
class MutablePgpKeyStore implements MutableKeyStore {
|
||||||
|
|
||||||
async loadKeyring(): Promise<void> {
|
async loadKeyring(): Promise<void> {
|
||||||
await keyring.load();
|
await keyring.load();
|
||||||
await keyring.store();
|
await keyring.store();
|
||||||
@ -77,8 +76,8 @@ class MutablePgpKeyStore implements MutableKeyStore{
|
|||||||
|
|
||||||
async isValidKey(key): Promise<boolean> {
|
async isValidKey(key): Promise<boolean> {
|
||||||
// There is supposed to be an openpgp.readKey() method but I can't find it?
|
// There is supposed to be an openpgp.readKey() method but I can't find it?
|
||||||
const _key = await openpgp.key.readArmored(key);
|
const testKey = await openpgp.key.readArmored(key);
|
||||||
return !_key.err;
|
return !testKey.err;
|
||||||
}
|
}
|
||||||
|
|
||||||
async isEncryptedPrivateKey(privateKey: any): Promise<boolean> {
|
async isEncryptedPrivateKey(privateKey: any): Promise<boolean> {
|
||||||
@ -93,8 +92,12 @@ class MutablePgpKeyStore implements MutableKeyStore{
|
|||||||
|
|
||||||
getFingerprint(): string {
|
getFingerprint(): string {
|
||||||
// TODO Handle multiple keys
|
// TODO Handle multiple keys
|
||||||
return keyring.privateKeys && keyring.privateKeys.keys[0] && keyring.privateKeys.keys[0].keyPacket &&
|
return (
|
||||||
keyring.privateKeys.keys[0].keyPacket.fingerprint;
|
keyring.privateKeys &&
|
||||||
|
keyring.privateKeys.keys[0] &&
|
||||||
|
keyring.privateKeys.keys[0].keyPacket &&
|
||||||
|
keyring.privateKeys.keys[0].keyPacket.fingerprint
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getKeyId(key: any): string {
|
getKeyId(key: any): string {
|
||||||
@ -103,7 +106,11 @@ class MutablePgpKeyStore implements MutableKeyStore{
|
|||||||
|
|
||||||
getPrivateKeyId(): string {
|
getPrivateKeyId(): string {
|
||||||
// TODO is there a library that comes with angular for doing this?
|
// TODO is there a library that comes with angular for doing this?
|
||||||
return keyring.privateKeys && keyring.privateKeys.keys[0] && keyring.privateKeys.keys[0].getKeyId().toHex();
|
return (
|
||||||
|
keyring.privateKeys &&
|
||||||
|
keyring.privateKeys.keys[0] &&
|
||||||
|
keyring.privateKeys.keys[0].getKeyId().toHex()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getKeysForId(keyId: string): Array<any> {
|
getKeysForId(keyId: string): Array<any> {
|
||||||
@ -159,7 +166,4 @@ class MutablePgpKeyStore implements MutableKeyStore{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export { MutablePgpKeyStore, MutableKeyStore };
|
||||||
MutablePgpKeyStore,
|
|
||||||
MutableKeyStore
|
|
||||||
};
|
|
||||||
|
@ -7,12 +7,12 @@ interface Signable {
|
|||||||
digest(): string;
|
digest(): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Signature = {
|
interface Signature {
|
||||||
engine: string
|
engine: string;
|
||||||
algo: string
|
algo: string;
|
||||||
data: string
|
data: string;
|
||||||
digest: string;
|
digest: string;
|
||||||
};
|
}
|
||||||
|
|
||||||
interface Signer {
|
interface Signer {
|
||||||
onsign(signature: Signature): void;
|
onsign(signature: Signature): void;
|
||||||
@ -24,7 +24,6 @@ interface Signer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class PGPSigner implements Signer {
|
class PGPSigner implements Signer {
|
||||||
|
|
||||||
engine = 'pgp';
|
engine = 'pgp';
|
||||||
algo = 'sha256';
|
algo = 'sha256';
|
||||||
dgst: string;
|
dgst: string;
|
||||||
@ -50,7 +49,9 @@ class PGPSigner implements Signer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public verify(digest: string, signature: Signature): void {
|
public verify(digest: string, signature: Signature): void {
|
||||||
openpgp.signature.readArmored(signature.data).then((sig) => {
|
openpgp.signature
|
||||||
|
.readArmored(signature.data)
|
||||||
|
.then((sig) => {
|
||||||
const opts = {
|
const opts = {
|
||||||
message: openpgp.cleartext.fromText(digest),
|
message: openpgp.cleartext.fromText(digest),
|
||||||
publicKeys: this.keyStore.getTrustedKeys(),
|
publicKeys: this.keyStore.getTrustedKeys(),
|
||||||
@ -65,10 +66,15 @@ class PGPSigner implements Signer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.loggingService.sendErrorLevelMessage(`Checked ${i} signature(s) but none valid`, this, {error: '404 Not found!'});
|
this.loggingService.sendErrorLevelMessage(
|
||||||
|
`Checked ${i} signature(s) but none valid`,
|
||||||
|
this,
|
||||||
|
{ error: '404 Not found!' }
|
||||||
|
);
|
||||||
this.onverify(false);
|
this.onverify(false);
|
||||||
});
|
});
|
||||||
}).catch((e) => {
|
})
|
||||||
|
.catch((e) => {
|
||||||
this.loggingService.sendErrorLevelMessage(e.message, this, { error: e });
|
this.loggingService.sendErrorLevelMessage(e.message, this, { error: e });
|
||||||
this.onverify(false);
|
this.onverify(false);
|
||||||
});
|
});
|
||||||
@ -86,7 +92,9 @@ class PGPSigner implements Signer {
|
|||||||
privateKeys: [pk],
|
privateKeys: [pk],
|
||||||
detached: true,
|
detached: true,
|
||||||
};
|
};
|
||||||
openpgp.sign(opts).then((s) => {
|
openpgp
|
||||||
|
.sign(opts)
|
||||||
|
.then((s) => {
|
||||||
this.signature = {
|
this.signature = {
|
||||||
engine: this.engine,
|
engine: this.engine,
|
||||||
algo: this.algo,
|
algo: this.algo,
|
||||||
@ -95,16 +103,12 @@ class PGPSigner implements Signer {
|
|||||||
digest,
|
digest,
|
||||||
};
|
};
|
||||||
this.onsign(this.signature);
|
this.onsign(this.signature);
|
||||||
}).catch((e) => {
|
})
|
||||||
|
.catch((e) => {
|
||||||
this.loggingService.sendErrorLevelMessage(e.message, this, { error: e });
|
this.loggingService.sendErrorLevelMessage(e.message, this, { error: e });
|
||||||
this.onsign(undefined);
|
this.onsign(undefined);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export { Signable, Signature, Signer, PGPSigner };
|
||||||
Signable,
|
|
||||||
Signature,
|
|
||||||
Signer,
|
|
||||||
PGPSigner
|
|
||||||
};
|
|
||||||
|
@ -9,7 +9,7 @@ import {HttpClient} from '@angular/common/http';
|
|||||||
import { HttpError } from '@app/_helpers/global-error-handler';
|
import { HttpError } from '@app/_helpers/global-error-handler';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
sessionToken: any;
|
sessionToken: any;
|
||||||
@ -95,7 +95,6 @@ export class AuthService {
|
|||||||
xhr.send();
|
xhr.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
login(): boolean {
|
login(): boolean {
|
||||||
if (this.sessionToken !== undefined) {
|
if (this.sessionToken !== undefined) {
|
||||||
try {
|
try {
|
||||||
@ -114,26 +113,30 @@ export class AuthService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async loginResponse(o: { challenge: string; realm: any }): Promise<any> {
|
||||||
async loginResponse(o: { challenge: string, realm: any }): Promise<any> {
|
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
const r = await signChallenge(o.challenge,
|
const r = await signChallenge(
|
||||||
|
o.challenge,
|
||||||
o.realm,
|
o.realm,
|
||||||
environment.cicMetaUrl,
|
environment.cicMetaUrl,
|
||||||
this.mutableKeyStore);
|
this.mutableKeyStore
|
||||||
|
);
|
||||||
const sessionTokenResult: boolean = await this.sendResponse(r);
|
const sessionTokenResult: boolean = await this.sendResponse(r);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof HttpError) {
|
if (error instanceof HttpError) {
|
||||||
if (error.status === 403) {
|
if (error.status === 403) {
|
||||||
this.errorDialogService.openDialog({ message: 'You are not authorized to use this system' });
|
this.errorDialogService.openDialog({
|
||||||
|
message: 'You are not authorized to use this system',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (error.status === 401) {
|
if (error.status === 401) {
|
||||||
this.errorDialogService.openDialog({
|
this.errorDialogService.openDialog({
|
||||||
message: 'Unable to authenticate with the service. ' +
|
message:
|
||||||
|
'Unable to authenticate with the service. ' +
|
||||||
'Please speak with the staff at Grassroots ' +
|
'Please speak with the staff at Grassroots ' +
|
||||||
'Economics for requesting access ' +
|
'Economics for requesting access ' +
|
||||||
'staff@grassrootseconomics.net.'
|
'staff@grassrootseconomics.net.',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,7 +167,11 @@ export class AuthService {
|
|||||||
const key = await this.mutableKeyStore.importPrivateKey(privateKeyArmored);
|
const key = await this.mutableKeyStore.importPrivateKey(privateKeyArmored);
|
||||||
localStorage.setItem(btoa('CICADA_PRIVATE_KEY'), privateKeyArmored);
|
localStorage.setItem(btoa('CICADA_PRIVATE_KEY'), privateKeyArmored);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.loggingService.sendErrorLevelMessage(`Failed to set key: ${err.message || err.statusText}`, this, {error: err});
|
this.loggingService.sendErrorLevelMessage(
|
||||||
|
`Failed to set key: ${err.message || err.statusText}`,
|
||||||
|
this,
|
||||||
|
{ error: err }
|
||||||
|
);
|
||||||
this.errorDialogService.openDialog({
|
this.errorDialogService.openDialog({
|
||||||
message: `Failed to set key: ${err.message || err.statusText}`,
|
message: `Failed to set key: ${err.message || err.statusText}`,
|
||||||
});
|
});
|
||||||
@ -177,18 +184,17 @@ export class AuthService {
|
|||||||
logout(): void {
|
logout(): void {
|
||||||
sessionStorage.removeItem(btoa('CICADA_SESSION_TOKEN'));
|
sessionStorage.removeItem(btoa('CICADA_SESSION_TOKEN'));
|
||||||
this.sessionToken = undefined;
|
this.sessionToken = undefined;
|
||||||
window.location.reload(true);
|
window.location.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
getTrustedUsers(): any {
|
getTrustedUsers(): any {
|
||||||
const trustedUsers: Array<any> = [];
|
const trustedUsers: Array<any> = [];
|
||||||
this.mutableKeyStore.getPublicKeys().forEach(key => trustedUsers.push(key.users[0].userId));
|
this.mutableKeyStore.getPublicKeys().forEach((key) => trustedUsers.push(key.users[0].userId));
|
||||||
return trustedUsers;
|
return trustedUsers;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPublicKeys(): Promise<any> {
|
async getPublicKeys(): Promise<any> {
|
||||||
return await fetch(environment.publicKeysUrl)
|
return await fetch(environment.publicKeysUrl).then((res) => {
|
||||||
.then(res => {
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
// TODO does angular recommend an error interface?
|
// TODO does angular recommend an error interface?
|
||||||
throw Error(`${res.statusText} - ${res.status}`);
|
throw Error(`${res.statusText} - ${res.status}`);
|
||||||
|
@ -9,9 +9,7 @@ describe('BlockSyncService', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
providers: [
|
providers: [{ provide: TransactionService, useClass: TransactionServiceStub }],
|
||||||
{ provide: TransactionService, useClass: TransactionServiceStub }
|
|
||||||
]
|
|
||||||
});
|
});
|
||||||
service = TestBed.inject(BlockSyncService);
|
service = TestBed.inject(BlockSyncService);
|
||||||
});
|
});
|
||||||
|
@ -8,7 +8,7 @@ import {LoggingService} from '@app/_services/logging.service';
|
|||||||
import { RegistryService } from '@app/_services/registry.service';
|
import { RegistryService } from '@app/_services/registry.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class BlockSyncService {
|
export class BlockSyncService {
|
||||||
readyStateTarget: number = 2;
|
readyStateTarget: number = 2;
|
||||||
@ -17,7 +17,7 @@ export class BlockSyncService {
|
|||||||
constructor(
|
constructor(
|
||||||
private transactionService: TransactionService,
|
private transactionService: TransactionService,
|
||||||
private loggingService: LoggingService,
|
private loggingService: LoggingService,
|
||||||
private registryService: RegistryService,
|
private registryService: RegistryService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
blockSync(address: string = null, offset: number = 0, limit: number = 100): void {
|
blockSync(address: string = null, offset: number = 0, limit: number = 100): void {
|
||||||
@ -43,7 +43,14 @@ export class BlockSyncService {
|
|||||||
settings.registry.load();
|
settings.registry.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
readyStateProcessor(settings: Settings, bit: number, address: string, offset: number, limit: number): void {
|
readyStateProcessor(
|
||||||
|
settings: Settings,
|
||||||
|
bit: number,
|
||||||
|
address: string,
|
||||||
|
offset: number,
|
||||||
|
limit: number
|
||||||
|
): void {
|
||||||
|
// tslint:disable-next-line:no-bitwise
|
||||||
this.readyState |= bit;
|
this.readyState |= bit;
|
||||||
if (this.readyStateTarget === this.readyState && this.readyStateTarget) {
|
if (this.readyStateTarget === this.readyState && this.readyStateTarget) {
|
||||||
const wHeadSync: Worker = new Worker('./../assets/js/block-sync/head.js');
|
const wHeadSync: Worker = new Worker('./../assets/js/block-sync/head.js');
|
||||||
@ -54,11 +61,17 @@ export class BlockSyncService {
|
|||||||
w3_provider: settings.w3.provider,
|
w3_provider: settings.w3.provider,
|
||||||
});
|
});
|
||||||
if (address === null) {
|
if (address === null) {
|
||||||
this.transactionService.getAllTransactions(offset, limit).pipe(first()).subscribe(res => {
|
this.transactionService
|
||||||
|
.getAllTransactions(offset, limit)
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((res) => {
|
||||||
this.fetcher(settings, res);
|
this.fetcher(settings, res);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.transactionService.getAddressTransactions(address, offset, limit).pipe(first()).subscribe(res => {
|
this.transactionService
|
||||||
|
.getAddressTransactions(address, offset, limit)
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((res) => {
|
||||||
this.fetcher(settings, res);
|
this.fetcher(settings, res);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -81,7 +94,14 @@ export class BlockSyncService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async scan(settings: Settings, lo: number, hi: number, bloomBlockBytes: Uint8Array, bloomBlocktxBytes: Uint8Array, bloomRounds: any): Promise<void> {
|
async scan(
|
||||||
|
settings: Settings,
|
||||||
|
lo: number,
|
||||||
|
hi: number,
|
||||||
|
bloomBlockBytes: Uint8Array,
|
||||||
|
bloomBlocktxBytes: Uint8Array,
|
||||||
|
bloomRounds: any
|
||||||
|
): Promise<void> {
|
||||||
const w: Worker = new Worker('./../assets/js/block-sync/ondemand.js');
|
const w: Worker = new Worker('./../assets/js/block-sync/ondemand.js');
|
||||||
w.onmessage = (m) => {
|
w.onmessage = (m) => {
|
||||||
settings.txHelper.processReceipt(m.data);
|
settings.txHelper.processReceipt(m.data);
|
||||||
@ -90,10 +110,7 @@ export class BlockSyncService {
|
|||||||
w3_provider: settings.w3.provider,
|
w3_provider: settings.w3.provider,
|
||||||
lo,
|
lo,
|
||||||
hi,
|
hi,
|
||||||
filters: [
|
filters: [bloomBlockBytes, bloomBlocktxBytes],
|
||||||
bloomBlockBytes,
|
|
||||||
bloomBlocktxBytes,
|
|
||||||
],
|
|
||||||
filter_rounds: bloomRounds,
|
filter_rounds: bloomRounds,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -101,12 +118,19 @@ export class BlockSyncService {
|
|||||||
fetcher(settings: Settings, transactionsInfo: any): void {
|
fetcher(settings: Settings, transactionsInfo: any): void {
|
||||||
const blockFilterBinstr: string = window.atob(transactionsInfo.block_filter);
|
const blockFilterBinstr: string = window.atob(transactionsInfo.block_filter);
|
||||||
const bOne: Uint8Array = new Uint8Array(blockFilterBinstr.length);
|
const bOne: Uint8Array = new Uint8Array(blockFilterBinstr.length);
|
||||||
bOne.map((e, i, v) => v[i] = blockFilterBinstr.charCodeAt(i));
|
bOne.map((e, i, v) => (v[i] = blockFilterBinstr.charCodeAt(i)));
|
||||||
|
|
||||||
const blocktxFilterBinstr: string = window.atob(transactionsInfo.blocktx_filter);
|
const blocktxFilterBinstr: string = window.atob(transactionsInfo.blocktx_filter);
|
||||||
const bTwo: Uint8Array = new Uint8Array(blocktxFilterBinstr.length);
|
const bTwo: Uint8Array = new Uint8Array(blocktxFilterBinstr.length);
|
||||||
bTwo.map((e, i, v) => v[i] = blocktxFilterBinstr.charCodeAt(i));
|
bTwo.map((e, i, v) => (v[i] = blocktxFilterBinstr.charCodeAt(i)));
|
||||||
|
|
||||||
settings.scanFilter(settings, transactionsInfo.low, transactionsInfo.high, bOne, bTwo, transactionsInfo.filter_rounds);
|
settings.scanFilter(
|
||||||
|
settings,
|
||||||
|
transactionsInfo.low,
|
||||||
|
transactionsInfo.high,
|
||||||
|
bOne,
|
||||||
|
bTwo,
|
||||||
|
transactionsInfo.filter_rounds
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,12 @@ import {MatDialog, MatDialogRef} from '@angular/material/dialog';
|
|||||||
import { ErrorDialogComponent } from '@app/shared/error-dialog/error-dialog.component';
|
import { ErrorDialogComponent } from '@app/shared/error-dialog/error-dialog.component';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class ErrorDialogService {
|
export class ErrorDialogService {
|
||||||
public isDialogOpen: boolean = false;
|
public isDialogOpen: boolean = false;
|
||||||
|
|
||||||
constructor(
|
constructor(public dialog: MatDialog) {}
|
||||||
public dialog: MatDialog,
|
|
||||||
) { }
|
|
||||||
|
|
||||||
openDialog(data): any {
|
openDialog(data): any {
|
||||||
if (this.isDialogOpen) {
|
if (this.isDialogOpen) {
|
||||||
@ -19,9 +17,9 @@ export class ErrorDialogService {
|
|||||||
this.isDialogOpen = true;
|
this.isDialogOpen = true;
|
||||||
const dialogRef: MatDialogRef<any> = this.dialog.open(ErrorDialogComponent, {
|
const dialogRef: MatDialogRef<any> = this.dialog.open(ErrorDialogComponent, {
|
||||||
width: '300px',
|
width: '300px',
|
||||||
data
|
data,
|
||||||
});
|
});
|
||||||
|
|
||||||
dialogRef.afterClosed().subscribe(() => this.isDialogOpen = false);
|
dialogRef.afterClosed().subscribe(() => (this.isDialogOpen = false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,10 @@ import {first} from 'rxjs/operators';
|
|||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class LocationService {
|
export class LocationService {
|
||||||
|
constructor(private httpClient: HttpClient) {}
|
||||||
constructor(
|
|
||||||
private httpClient: HttpClient,
|
|
||||||
) { }
|
|
||||||
|
|
||||||
getAreaNames(): Observable<any> {
|
getAreaNames(): Observable<any> {
|
||||||
return this.httpClient.get(`${environment.cicMetaUrl}/areanames`);
|
return this.httpClient.get(`${environment.cicMetaUrl}/areanames`);
|
||||||
@ -26,6 +23,8 @@ export class LocationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getAreaTypeByArea(area: string): Observable<any> {
|
getAreaTypeByArea(area: string): Observable<any> {
|
||||||
return this.httpClient.get(`${environment.cicMetaUrl}/areatypes/${area.toLowerCase()}`).pipe(first());
|
return this.httpClient
|
||||||
|
.get(`${environment.cicMetaUrl}/areatypes/${area.toLowerCase()}`)
|
||||||
|
.pipe(first());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import {Injectable, isDevMode} from '@angular/core';
|
|||||||
import { NGXLogger } from 'ngx-logger';
|
import { NGXLogger } from 'ngx-logger';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class LoggingService {
|
export class LoggingService {
|
||||||
env: string;
|
env: string;
|
||||||
|
@ -5,13 +5,18 @@ import {CICRegistry, FileGetter} from 'cic-client';
|
|||||||
import { HttpGetter } from '@app/_helpers';
|
import { HttpGetter } from '@app/_helpers';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class RegistryService {
|
export class RegistryService {
|
||||||
web3: Web3 = new Web3(environment.web3Provider);
|
web3: Web3 = new Web3(environment.web3Provider);
|
||||||
fileGetter: FileGetter = new HttpGetter();
|
fileGetter: FileGetter = new HttpGetter();
|
||||||
registry: CICRegistry = new CICRegistry(this.web3, environment.registryAddress, 'CICRegistry', this.fileGetter,
|
registry: CICRegistry = new CICRegistry(
|
||||||
['../../assets/js/block-sync/data']);
|
this.web3,
|
||||||
|
environment.registryAddress,
|
||||||
|
'CICRegistry',
|
||||||
|
this.fileGetter,
|
||||||
|
['../../assets/js/block-sync/data']
|
||||||
|
);
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.registry.declaratorHelper.addTrust(environment.trustedDeclaratorAddress);
|
this.registry.declaratorHelper.addTrust(environment.trustedDeclaratorAddress);
|
||||||
|
@ -7,21 +7,20 @@ import {HttpClient} from '@angular/common/http';
|
|||||||
import { RegistryService } from '@app/_services/registry.service';
|
import { RegistryService } from '@app/_services/registry.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class TokenService {
|
export class TokenService {
|
||||||
registry: CICRegistry;
|
registry: CICRegistry;
|
||||||
tokenRegistry: TokenRegistry;
|
tokenRegistry: TokenRegistry;
|
||||||
LoadEvent: EventEmitter<number> = new EventEmitter<number>();
|
LoadEvent: EventEmitter<number> = new EventEmitter<number>();
|
||||||
|
|
||||||
constructor(
|
constructor(private httpClient: HttpClient, private registryService: RegistryService) {
|
||||||
private httpClient: HttpClient,
|
|
||||||
private registryService: RegistryService,
|
|
||||||
) {
|
|
||||||
this.registry = registryService.getRegistry();
|
this.registry = registryService.getRegistry();
|
||||||
this.registry.load();
|
this.registry.load();
|
||||||
this.registry.onload = async (address: string): Promise<void> => {
|
this.registry.onload = async (address: string): Promise<void> => {
|
||||||
this.tokenRegistry = new TokenRegistry(await this.registry.getContractAddressByName('TokenRegistry'));
|
this.tokenRegistry = new TokenRegistry(
|
||||||
|
await this.registry.getContractAddressByName('TokenRegistry')
|
||||||
|
);
|
||||||
this.LoadEvent.next(Date.now());
|
this.LoadEvent.next(Date.now());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ describe('TransactionService', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [HttpClientTestingModule]
|
imports: [HttpClientTestingModule],
|
||||||
});
|
});
|
||||||
httpClient = TestBed.inject(HttpClient);
|
httpClient = TestBed.inject(HttpClient);
|
||||||
httpTestingController = TestBed.inject(HttpTestingController);
|
httpTestingController = TestBed.inject(HttpTestingController);
|
||||||
|
@ -20,7 +20,7 @@ import Web3 from 'web3';
|
|||||||
const vCard = require('vcard-parser');
|
const vCard = require('vcard-parser');
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class TransactionService {
|
export class TransactionService {
|
||||||
transactions: any[] = [];
|
transactions: any[] = [];
|
||||||
@ -35,7 +35,7 @@ export class TransactionService {
|
|||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
private userService: UserService,
|
private userService: UserService,
|
||||||
private loggingService: LoggingService,
|
private loggingService: LoggingService,
|
||||||
private registryService: RegistryService,
|
private registryService: RegistryService
|
||||||
) {
|
) {
|
||||||
this.web3 = this.registryService.getWeb3();
|
this.web3 = this.registryService.getWeb3();
|
||||||
this.registry = registryService.getRegistry();
|
this.registry = registryService.getRegistry();
|
||||||
@ -51,36 +51,58 @@ export class TransactionService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async setTransaction(transaction, cacheSize: number): Promise<void> {
|
async setTransaction(transaction, cacheSize: number): Promise<void> {
|
||||||
if (this.transactions.find(cachedTx => cachedTx.tx.txHash === transaction.tx.txHash)) { return; }
|
if (this.transactions.find((cachedTx) => cachedTx.tx.txHash === transaction.tx.txHash)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
transaction.value = Number(transaction.value);
|
transaction.value = Number(transaction.value);
|
||||||
transaction.type = 'transaction';
|
transaction.type = 'transaction';
|
||||||
try {
|
try {
|
||||||
this.userService.getAccountDetailsFromMeta(await User.toKey(transaction.from)).pipe(first()).subscribe((res) => {
|
this.userService
|
||||||
|
.getAccountDetailsFromMeta(await User.toKey(transaction.from))
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe(
|
||||||
|
(res) => {
|
||||||
transaction.sender = this.getAccountInfo(res.body);
|
transaction.sender = this.getAccountInfo(res.body);
|
||||||
}, error => {
|
},
|
||||||
|
(error) => {
|
||||||
transaction.sender = defaultAccount;
|
transaction.sender = defaultAccount;
|
||||||
});
|
}
|
||||||
this.userService.getAccountDetailsFromMeta(await User.toKey(transaction.to)).pipe(first()).subscribe((res) => {
|
);
|
||||||
|
this.userService
|
||||||
|
.getAccountDetailsFromMeta(await User.toKey(transaction.to))
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe(
|
||||||
|
(res) => {
|
||||||
transaction.recipient = this.getAccountInfo(res.body);
|
transaction.recipient = this.getAccountInfo(res.body);
|
||||||
}, error => {
|
},
|
||||||
|
(error) => {
|
||||||
transaction.recipient = defaultAccount;
|
transaction.recipient = defaultAccount;
|
||||||
});
|
}
|
||||||
|
);
|
||||||
} finally {
|
} finally {
|
||||||
this.addTransaction(transaction, cacheSize);
|
this.addTransaction(transaction, cacheSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async setConversion(conversion, cacheSize): Promise<void> {
|
async setConversion(conversion, cacheSize): Promise<void> {
|
||||||
if (this.transactions.find(cachedTx => cachedTx.tx.txHash === conversion.tx.txHash)) { return; }
|
if (this.transactions.find((cachedTx) => cachedTx.tx.txHash === conversion.tx.txHash)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
conversion.type = 'conversion';
|
conversion.type = 'conversion';
|
||||||
conversion.fromValue = Number(conversion.fromValue);
|
conversion.fromValue = Number(conversion.fromValue);
|
||||||
conversion.toValue = Number(conversion.toValue);
|
conversion.toValue = Number(conversion.toValue);
|
||||||
try {
|
try {
|
||||||
this.userService.getAccountDetailsFromMeta(await User.toKey(conversion.trader)).pipe(first()).subscribe((res) => {
|
this.userService
|
||||||
|
.getAccountDetailsFromMeta(await User.toKey(conversion.trader))
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe(
|
||||||
|
(res) => {
|
||||||
conversion.sender = conversion.recipient = this.getAccountInfo(res.body);
|
conversion.sender = conversion.recipient = this.getAccountInfo(res.body);
|
||||||
}, error => {
|
},
|
||||||
|
(error) => {
|
||||||
conversion.sender = conversion.recipient = defaultAccount;
|
conversion.sender = conversion.recipient = defaultAccount;
|
||||||
});
|
}
|
||||||
|
);
|
||||||
} finally {
|
} finally {
|
||||||
this.addTransaction(conversion, cacheSize);
|
this.addTransaction(conversion, cacheSize);
|
||||||
}
|
}
|
||||||
@ -100,19 +122,29 @@ export class TransactionService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getAccountInfo(account: string): any {
|
getAccountInfo(account: string): any {
|
||||||
let accountInfo = Envelope.fromJSON(JSON.stringify(account)).unwrap().m.data;
|
const accountInfo = Envelope.fromJSON(JSON.stringify(account)).unwrap().m.data;
|
||||||
accountInfo.vcard = vCard.parse(atob(accountInfo.vcard));
|
accountInfo.vcard = vCard.parse(atob(accountInfo.vcard));
|
||||||
return accountInfo;
|
return accountInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
async transferRequest(tokenAddress: string, senderAddress: string, recipientAddress: string, value: number): Promise<any> {
|
async transferRequest(
|
||||||
const transferAuthAddress = await this.registry.getContractAddressByName('TransferAuthorization');
|
tokenAddress: string,
|
||||||
|
senderAddress: string,
|
||||||
|
recipientAddress: string,
|
||||||
|
value: number
|
||||||
|
): Promise<any> {
|
||||||
|
const transferAuthAddress = await this.registry.getContractAddressByName(
|
||||||
|
'TransferAuthorization'
|
||||||
|
);
|
||||||
const hashFunction = new Keccak(256);
|
const hashFunction = new Keccak(256);
|
||||||
hashFunction.update('createRequest(address,address,address,uint256)');
|
hashFunction.update('createRequest(address,address,address,uint256)');
|
||||||
const hash = hashFunction.digest();
|
const hash = hashFunction.digest();
|
||||||
const methodSignature = hash.toString('hex').substring(0, 8);
|
const methodSignature = hash.toString('hex').substring(0, 8);
|
||||||
const abiCoder = new utils.AbiCoder();
|
const abiCoder = new utils.AbiCoder();
|
||||||
const abi = await abiCoder.encode(['address', 'address', 'address', 'uint256'], [senderAddress, recipientAddress, tokenAddress, value]);
|
const abi = await abiCoder.encode(
|
||||||
|
['address', 'address', 'address', 'uint256'],
|
||||||
|
[senderAddress, recipientAddress, tokenAddress, value]
|
||||||
|
);
|
||||||
const data = fromHex(methodSignature + strip0x(abi));
|
const data = fromHex(methodSignature + strip0x(abi));
|
||||||
const tx = new Tx(environment.bloxbergChainId);
|
const tx = new Tx(environment.bloxbergChainId);
|
||||||
tx.nonce = await this.web3.eth.getTransactionCount(senderAddress);
|
tx.nonce = await this.web3.eth.getTransactionCount(senderAddress);
|
||||||
|
@ -11,7 +11,7 @@ describe('UserService', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [HttpClientTestingModule]
|
imports: [HttpClientTestingModule],
|
||||||
});
|
});
|
||||||
httpClient = TestBed.inject(HttpClient);
|
httpClient = TestBed.inject(HttpClient);
|
||||||
httpTestingController = TestBed.inject(HttpTestingController);
|
httpTestingController = TestBed.inject(HttpTestingController);
|
||||||
@ -34,7 +34,7 @@ describe('UserService', () => {
|
|||||||
failedPinAttempts: 1,
|
failedPinAttempts: 1,
|
||||||
status: 'approved',
|
status: 'approved',
|
||||||
bio: 'Bodaboda',
|
bio: 'Bodaboda',
|
||||||
gender: 'male'
|
gender: 'male',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ describe('UserService', () => {
|
|||||||
user: 'Tom',
|
user: 'Tom',
|
||||||
role: 'enroller',
|
role: 'enroller',
|
||||||
action: 'Disburse RSV 100',
|
action: 'Disburse RSV 100',
|
||||||
approval: false
|
approval: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ describe('UserService', () => {
|
|||||||
user: 'Tom',
|
user: 'Tom',
|
||||||
role: 'enroller',
|
role: 'enroller',
|
||||||
action: 'Disburse RSV 100',
|
action: 'Disburse RSV 100',
|
||||||
approval: true
|
approval: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ describe('UserService', () => {
|
|||||||
user: 'Christine',
|
user: 'Christine',
|
||||||
role: 'admin',
|
role: 'admin',
|
||||||
action: 'Change user phone number',
|
action: 'Change user phone number',
|
||||||
approval: false
|
approval: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -17,7 +17,7 @@ import {add0x} from '@src/assets/js/ethtx/dist/hex';
|
|||||||
const vCard = require('vcard-parser');
|
const vCard = require('vcard-parser');
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class UserService {
|
export class UserService {
|
||||||
headers: HttpHeaders = new HttpHeaders({ 'x-cic-automerge': 'client' });
|
headers: HttpHeaders = new HttpHeaders({ 'x-cic-automerge': 'client' });
|
||||||
@ -26,7 +26,9 @@ export class UserService {
|
|||||||
registry: CICRegistry;
|
registry: CICRegistry;
|
||||||
|
|
||||||
accounts: Array<AccountDetails> = [];
|
accounts: Array<AccountDetails> = [];
|
||||||
private accountsList: BehaviorSubject<Array<AccountDetails>> = new BehaviorSubject<Array<AccountDetails>>(this.accounts);
|
private accountsList: BehaviorSubject<Array<AccountDetails>> = new BehaviorSubject<
|
||||||
|
Array<AccountDetails>
|
||||||
|
>(this.accounts);
|
||||||
accountsSubject: Observable<Array<AccountDetails>> = this.accountsList.asObservable();
|
accountsSubject: Observable<Array<AccountDetails>> = this.accountsList.asObservable();
|
||||||
|
|
||||||
actions: Array<any> = [];
|
actions: Array<any> = [];
|
||||||
@ -38,7 +40,7 @@ export class UserService {
|
|||||||
private loggingService: LoggingService,
|
private loggingService: LoggingService,
|
||||||
private tokenService: TokenService,
|
private tokenService: TokenService,
|
||||||
private registryService: RegistryService,
|
private registryService: RegistryService,
|
||||||
private authService: AuthService,
|
private authService: AuthService
|
||||||
) {
|
) {
|
||||||
this.authService.init().then(() => {
|
this.authService.init().then(() => {
|
||||||
this.keystore = authService.mutableKeyStore;
|
this.keystore = authService.mutableKeyStore;
|
||||||
@ -62,16 +64,26 @@ export class UserService {
|
|||||||
return this.httpClient.get(`${environment.cicUssdUrl}/accounts/locked/${offset}/${limit}`);
|
return this.httpClient.get(`${environment.cicUssdUrl}/accounts/locked/${offset}/${limit}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async changeAccountInfo(address: string, name: string, phoneNumber: string, age: string, type: string, bio: string, gender: string,
|
async changeAccountInfo(
|
||||||
businessCategory: string, userLocation: string, location: string, locationType: string
|
address: string,
|
||||||
|
name: string,
|
||||||
|
phoneNumber: string,
|
||||||
|
age: string,
|
||||||
|
type: string,
|
||||||
|
bio: string,
|
||||||
|
gender: string,
|
||||||
|
businessCategory: string,
|
||||||
|
userLocation: string,
|
||||||
|
location: string,
|
||||||
|
locationType: string
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
const accountInfo: any = {
|
const accountInfo: any = {
|
||||||
vcard: {
|
vcard: {
|
||||||
fn: [{}],
|
fn: [{}],
|
||||||
n: [{}],
|
n: [{}],
|
||||||
tel: [{}]
|
tel: [{}],
|
||||||
},
|
},
|
||||||
location: {}
|
location: {},
|
||||||
};
|
};
|
||||||
accountInfo.vcard.fn[0].value = name;
|
accountInfo.vcard.fn[0].value = name;
|
||||||
accountInfo.vcard.n[0].value = name.split(' ');
|
accountInfo.vcard.n[0].value = name.split(' ');
|
||||||
@ -87,33 +99,52 @@ export class UserService {
|
|||||||
await vcardValidation(accountInfo.vcard);
|
await vcardValidation(accountInfo.vcard);
|
||||||
accountInfo.vcard = btoa(vCard.generate(accountInfo.vcard));
|
accountInfo.vcard = btoa(vCard.generate(accountInfo.vcard));
|
||||||
const accountKey: string = await User.toKey(address);
|
const accountKey: string = await User.toKey(address);
|
||||||
this.getAccountDetailsFromMeta(accountKey).pipe(first()).subscribe(async res => {
|
this.getAccountDetailsFromMeta(accountKey)
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe(
|
||||||
|
async (res) => {
|
||||||
const syncableAccount: Syncable = Envelope.fromJSON(JSON.stringify(res)).unwrap();
|
const syncableAccount: Syncable = Envelope.fromJSON(JSON.stringify(res)).unwrap();
|
||||||
const update: Array<ArgPair> = [];
|
const update: Array<ArgPair> = [];
|
||||||
for (const prop in accountInfo) {
|
for (const prop of Object.keys(accountInfo)) {
|
||||||
update.push(new ArgPair(prop, accountInfo[prop]));
|
update.push(new ArgPair(prop, accountInfo[prop]));
|
||||||
}
|
}
|
||||||
syncableAccount.update(update, 'client-branch');
|
syncableAccount.update(update, 'client-branch');
|
||||||
await personValidation(syncableAccount.m.data);
|
await personValidation(syncableAccount.m.data);
|
||||||
await this.updateMeta(syncableAccount, accountKey, this.headers);
|
await this.updateMeta(syncableAccount, accountKey, this.headers);
|
||||||
}, async error => {
|
},
|
||||||
this.loggingService.sendErrorLevelMessage('Can\'t find account info in meta service', this, {error});
|
async (error) => {
|
||||||
|
this.loggingService.sendErrorLevelMessage(
|
||||||
|
'Cannot find account info in meta service',
|
||||||
|
this,
|
||||||
|
{ error }
|
||||||
|
);
|
||||||
const syncableAccount: Syncable = new Syncable(accountKey, accountInfo);
|
const syncableAccount: Syncable = new Syncable(accountKey, accountInfo);
|
||||||
await this.updateMeta(syncableAccount, accountKey, this.headers);
|
await this.updateMeta(syncableAccount, accountKey, this.headers);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
return accountKey;
|
return accountKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateMeta(syncableAccount: Syncable, accountKey: string, headers: HttpHeaders): Promise<any> {
|
async updateMeta(
|
||||||
|
syncableAccount: Syncable,
|
||||||
|
accountKey: string,
|
||||||
|
headers: HttpHeaders
|
||||||
|
): Promise<any> {
|
||||||
const envelope: Envelope = await this.wrap(syncableAccount, this.signer);
|
const envelope: Envelope = await this.wrap(syncableAccount, this.signer);
|
||||||
const reqBody: string = envelope.toJSON();
|
const reqBody: string = envelope.toJSON();
|
||||||
this.httpClient.put(`${environment.cicMetaUrl}/${accountKey}`, reqBody , { headers }).pipe(first()).subscribe(res => {
|
this.httpClient
|
||||||
|
.put(`${environment.cicMetaUrl}/${accountKey}`, reqBody, { headers })
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((res) => {
|
||||||
this.loggingService.sendInfoLevelMessage(`Response: ${res}`);
|
this.loggingService.sendInfoLevelMessage(`Response: ${res}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getActions(): void {
|
getActions(): void {
|
||||||
this.httpClient.get(`${environment.cicCacheUrl}/actions`).pipe(first()).subscribe(res => this.actionsList.next(res));
|
this.httpClient
|
||||||
|
.get(`${environment.cicCacheUrl}/actions`)
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((res) => this.actionsList.next(res));
|
||||||
}
|
}
|
||||||
|
|
||||||
getActionById(id: string): Observable<any> {
|
getActionById(id: string): Observable<any> {
|
||||||
@ -148,22 +179,33 @@ export class UserService {
|
|||||||
|
|
||||||
async loadAccounts(limit: number = 100, offset: number = 0): Promise<void> {
|
async loadAccounts(limit: number = 100, offset: number = 0): Promise<void> {
|
||||||
this.resetAccountsList();
|
this.resetAccountsList();
|
||||||
const accountIndexAddress: string = await this.registry.getContractAddressByName('AccountRegistry');
|
const accountIndexAddress: string = await this.registry.getContractAddressByName(
|
||||||
|
'AccountRegistry'
|
||||||
|
);
|
||||||
const accountIndexQuery = new AccountIndex(accountIndexAddress);
|
const accountIndexQuery = new AccountIndex(accountIndexAddress);
|
||||||
const accountAddresses: Array<string> = await accountIndexQuery.last(await accountIndexQuery.totalAccounts());
|
const accountAddresses: Array<string> = await accountIndexQuery.last(
|
||||||
|
await accountIndexQuery.totalAccounts()
|
||||||
|
);
|
||||||
this.loggingService.sendInfoLevelMessage(accountAddresses);
|
this.loggingService.sendInfoLevelMessage(accountAddresses);
|
||||||
for (const accountAddress of accountAddresses.slice(offset, offset + limit)) {
|
for (const accountAddress of accountAddresses.slice(offset, offset + limit)) {
|
||||||
await this.getAccountByAddress(accountAddress, limit);
|
await this.getAccountByAddress(accountAddress, limit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAccountByAddress(accountAddress: string, limit: number = 100): Promise<Observable<AccountDetails>> {
|
async getAccountByAddress(
|
||||||
let accountSubject: Subject<any> = new Subject<any>();
|
accountAddress: string,
|
||||||
this.getAccountDetailsFromMeta(await User.toKey(add0x(accountAddress))).pipe(first()).subscribe(async res => {
|
limit: number = 100
|
||||||
|
): Promise<Observable<AccountDetails>> {
|
||||||
|
const accountSubject: Subject<any> = new Subject<any>();
|
||||||
|
this.getAccountDetailsFromMeta(await User.toKey(add0x(accountAddress)))
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe(async (res) => {
|
||||||
const account: Syncable = Envelope.fromJSON(JSON.stringify(res)).unwrap();
|
const account: Syncable = Envelope.fromJSON(JSON.stringify(res)).unwrap();
|
||||||
const accountInfo = account.m.data;
|
const accountInfo = account.m.data;
|
||||||
await personValidation(accountInfo);
|
await personValidation(accountInfo);
|
||||||
accountInfo.balance = await this.tokenService.getTokenBalance(accountInfo.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0]);
|
accountInfo.balance = await this.tokenService.getTokenBalance(
|
||||||
|
accountInfo.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0]
|
||||||
|
);
|
||||||
accountInfo.vcard = vCard.parse(atob(accountInfo.vcard));
|
accountInfo.vcard = vCard.parse(atob(accountInfo.vcard));
|
||||||
await vcardValidation(accountInfo.vcard);
|
await vcardValidation(accountInfo.vcard);
|
||||||
this.accounts.unshift(accountInfo);
|
this.accounts.unshift(accountInfo);
|
||||||
@ -176,13 +218,18 @@ export class UserService {
|
|||||||
return accountSubject.asObservable();
|
return accountSubject.asObservable();
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAccountByPhone(phoneNumber: string, limit: number = 100): Promise<Observable<AccountDetails>> {
|
async getAccountByPhone(
|
||||||
let accountSubject: Subject<any> = new Subject<any>();
|
phoneNumber: string,
|
||||||
this.getAccountDetailsFromMeta(await Phone.toKey(phoneNumber)).pipe(first()).subscribe(async res => {
|
limit: number = 100
|
||||||
|
): Promise<Observable<AccountDetails>> {
|
||||||
|
const accountSubject: Subject<any> = new Subject<any>();
|
||||||
|
this.getAccountDetailsFromMeta(await Phone.toKey(phoneNumber))
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe(async (res) => {
|
||||||
const response: Syncable = Envelope.fromJSON(JSON.stringify(res)).unwrap();
|
const response: Syncable = Envelope.fromJSON(JSON.stringify(res)).unwrap();
|
||||||
const address: string = response.m.data;
|
const address: string = response.m.data;
|
||||||
const account: Observable<AccountDetails> = await this.getAccountByAddress(address, limit);
|
const account: Observable<AccountDetails> = await this.getAccountByAddress(address, limit);
|
||||||
account.subscribe(result => {
|
account.subscribe((result) => {
|
||||||
accountSubject.next(result);
|
accountSubject.next(result);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -194,7 +241,9 @@ export class UserService {
|
|||||||
this.accountsList.next(this.accounts);
|
this.accountsList.next(this.accounts);
|
||||||
}
|
}
|
||||||
|
|
||||||
searchAccountByName(name: string): any { return; }
|
searchAccountByName(name: string): any {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
getCategories(): Observable<any> {
|
getCategories(): Observable<any> {
|
||||||
return this.httpClient.get(`${environment.cicMetaUrl}/categories`);
|
return this.httpClient.get(`${environment.cicMetaUrl}/categories`);
|
||||||
|
@ -3,15 +3,21 @@ import {Routes, RouterModule, PreloadAllModules} from '@angular/router';
|
|||||||
import { AuthGuard } from '@app/_guards';
|
import { AuthGuard } from '@app/_guards';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{ path: 'auth', loadChildren: () => import('@app/auth/auth.module').then(m => m.AuthModule) },
|
{ path: 'auth', loadChildren: () => import('@app/auth/auth.module').then((m) => m.AuthModule) },
|
||||||
{ path: '', loadChildren: () => import('@pages/pages.module').then(m => m.PagesModule), canActivate: [AuthGuard] },
|
{
|
||||||
{ path: '**', redirectTo: '', pathMatch: 'full' }
|
path: '',
|
||||||
|
loadChildren: () => import('@pages/pages.module').then((m) => m.PagesModule),
|
||||||
|
canActivate: [AuthGuard],
|
||||||
|
},
|
||||||
|
{ path: '**', redirectTo: '', pathMatch: 'full' },
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forRoot(routes, {
|
imports: [
|
||||||
preloadingStrategy: PreloadAllModules
|
RouterModule.forRoot(routes, {
|
||||||
})],
|
preloadingStrategy: PreloadAllModules,
|
||||||
exports: [RouterModule]
|
}),
|
||||||
|
],
|
||||||
|
exports: [RouterModule],
|
||||||
})
|
})
|
||||||
export class AppRoutingModule {}
|
export class AppRoutingModule {}
|
||||||
|
@ -2,23 +2,19 @@ import { TestBed } from '@angular/core/testing';
|
|||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { AppComponent } from '@app/app.component';
|
import { AppComponent } from '@app/app.component';
|
||||||
import { TransactionService } from '@app/_services';
|
import { TransactionService } from '@app/_services';
|
||||||
import {FooterStubComponent, SidebarStubComponent, TopbarStubComponent, TransactionServiceStub} from '@src/testing';
|
import {
|
||||||
|
FooterStubComponent,
|
||||||
|
SidebarStubComponent,
|
||||||
|
TopbarStubComponent,
|
||||||
|
TransactionServiceStub,
|
||||||
|
} from '@src/testing';
|
||||||
|
|
||||||
describe('AppComponent', () => {
|
describe('AppComponent', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [RouterTestingModule],
|
||||||
RouterTestingModule
|
declarations: [AppComponent, FooterStubComponent, SidebarStubComponent, TopbarStubComponent],
|
||||||
],
|
providers: [{ provide: TransactionService, useClass: TransactionServiceStub }],
|
||||||
declarations: [
|
|
||||||
AppComponent,
|
|
||||||
FooterStubComponent,
|
|
||||||
SidebarStubComponent,
|
|
||||||
TopbarStubComponent
|
|
||||||
],
|
|
||||||
providers: [
|
|
||||||
{ provide: TransactionService, useClass: TransactionServiceStub }
|
|
||||||
]
|
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
import {ChangeDetectionStrategy, Component, HostListener, OnInit} from '@angular/core';
|
import {ChangeDetectionStrategy, Component, HostListener, OnInit} from '@angular/core';
|
||||||
import {AuthService, ErrorDialogService, LoggingService, TransactionService} from '@app/_services';
|
import {
|
||||||
|
AuthService,
|
||||||
|
ErrorDialogService,
|
||||||
|
LoggingService,
|
||||||
|
TransactionService,
|
||||||
|
} from '@app/_services';
|
||||||
import { catchError } from 'rxjs/operators';
|
import { catchError } from 'rxjs/operators';
|
||||||
import { SwUpdate } from '@angular/service-worker';
|
import { SwUpdate } from '@angular/service-worker';
|
||||||
|
|
||||||
@ -7,7 +12,7 @@ import {SwUpdate} from '@angular/service-worker';
|
|||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
styleUrls: ['./app.component.scss'],
|
styleUrls: ['./app.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class AppComponent implements OnInit {
|
export class AppComponent implements OnInit {
|
||||||
title = 'CICADA';
|
title = 'CICADA';
|
||||||
@ -33,11 +38,13 @@ export class AppComponent implements OnInit {
|
|||||||
const publicKeys = await this.authService.getPublicKeys();
|
const publicKeys = await this.authService.getPublicKeys();
|
||||||
await this.authService.mutableKeyStore.importPublicKey(publicKeys);
|
await this.authService.mutableKeyStore.importPublicKey(publicKeys);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.errorDialogService.openDialog({message: 'Trusted keys endpoint can\'t be reached. Please try again later.'});
|
this.errorDialogService.openDialog({
|
||||||
|
message: 'Trusted keys endpoint cannot be reached. Please try again later.',
|
||||||
|
});
|
||||||
// TODO do something to halt user progress...show a sad cicada page 🦗?
|
// TODO do something to halt user progress...show a sad cicada page 🦗?
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
this.mediaQuery.addListener(this.onResize);
|
this.mediaQuery.addEventListener('change', this.onResize);
|
||||||
this.onResize(this.mediaQuery);
|
this.onResize(this.mediaQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,10 +5,7 @@ import {AppRoutingModule} from '@app/app-routing.module';
|
|||||||
import { AppComponent } from '@app/app.component';
|
import { AppComponent } from '@app/app.component';
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
|
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
|
||||||
import {
|
import { GlobalErrorHandler, MockBackendProvider } from '@app/_helpers';
|
||||||
GlobalErrorHandler,
|
|
||||||
MockBackendProvider,
|
|
||||||
} from '@app/_helpers';
|
|
||||||
import { DataTablesModule } from 'angular-datatables';
|
import { DataTablesModule } from 'angular-datatables';
|
||||||
import { SharedModule } from '@app/shared/shared.module';
|
import { SharedModule } from '@app/shared/shared.module';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
@ -20,9 +17,7 @@ import {MutablePgpKeyStore} from '@app/_pgp';
|
|||||||
import { ServiceWorkerModule } from '@angular/service-worker';
|
import { ServiceWorkerModule } from '@angular/service-worker';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [AppComponent],
|
||||||
AppComponent
|
|
||||||
],
|
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
AppRoutingModule,
|
AppRoutingModule,
|
||||||
@ -35,9 +30,9 @@ import { ServiceWorkerModule } from '@angular/service-worker';
|
|||||||
level: environment.logLevel,
|
level: environment.logLevel,
|
||||||
serverLogLevel: environment.serverLogLevel,
|
serverLogLevel: environment.serverLogLevel,
|
||||||
serverLoggingUrl: `${environment.loggingUrl}/api/logs/`,
|
serverLoggingUrl: `${environment.loggingUrl}/api/logs/`,
|
||||||
disableConsoleLogging: false
|
disableConsoleLogging: false,
|
||||||
}),
|
}),
|
||||||
ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production })
|
ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }),
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
AuthGuard,
|
AuthGuard,
|
||||||
@ -49,6 +44,6 @@ import { ServiceWorkerModule } from '@angular/service-worker';
|
|||||||
{ provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true },
|
{ provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true },
|
||||||
{ provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true },
|
{ provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true },
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent],
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import { PasswordToggleDirective } from '@app/auth/_directives/password-toggle.directive';
|
import { PasswordToggleDirective } from '@app/auth/_directives/password-toggle.directive';
|
||||||
import { ElementRef, Renderer2 } from '@angular/core';
|
import { ElementRef, Renderer2 } from '@angular/core';
|
||||||
|
|
||||||
|
// tslint:disable-next-line:prefer-const
|
||||||
let elementRef: ElementRef;
|
let elementRef: ElementRef;
|
||||||
|
// tslint:disable-next-line:prefer-const
|
||||||
let renderer: Renderer2;
|
let renderer: Renderer2;
|
||||||
|
|
||||||
describe('PasswordToggleDirective', () => {
|
describe('PasswordToggleDirective', () => {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Directive, ElementRef, Input, Renderer2 } from '@angular/core';
|
import { Directive, ElementRef, Input, Renderer2 } from '@angular/core';
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: '[appPasswordToggle]'
|
selector: '[appPasswordToggle]',
|
||||||
})
|
})
|
||||||
export class PasswordToggleDirective {
|
export class PasswordToggleDirective {
|
||||||
@Input()
|
@Input()
|
||||||
@ -10,10 +10,7 @@ export class PasswordToggleDirective {
|
|||||||
@Input()
|
@Input()
|
||||||
iconId: string;
|
iconId: string;
|
||||||
|
|
||||||
constructor(
|
constructor(private elementRef: ElementRef, private renderer: Renderer2) {
|
||||||
private elementRef: ElementRef,
|
|
||||||
private renderer: Renderer2,
|
|
||||||
) {
|
|
||||||
this.renderer.listen(this.elementRef.nativeElement, 'click', () => {
|
this.renderer.listen(this.elementRef.nativeElement, 'click', () => {
|
||||||
this.togglePasswordVisibility();
|
this.togglePasswordVisibility();
|
||||||
});
|
});
|
||||||
|
@ -10,6 +10,6 @@ const routes: Routes = [
|
|||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forChild(routes)],
|
imports: [RouterModule.forChild(routes)],
|
||||||
exports: [RouterModule]
|
exports: [RouterModule],
|
||||||
})
|
})
|
||||||
export class AuthRoutingModule {}
|
export class AuthRoutingModule {}
|
||||||
|
@ -8,9 +8,8 @@ describe('AuthComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ AuthComponent ]
|
declarations: [AuthComponent],
|
||||||
})
|
}).compileComponents();
|
||||||
.compileComponents();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -8,7 +8,7 @@ import {Router} from '@angular/router';
|
|||||||
selector: 'app-auth',
|
selector: 'app-auth',
|
||||||
templateUrl: './auth.component.html',
|
templateUrl: './auth.component.html',
|
||||||
styleUrls: ['./auth.component.scss'],
|
styleUrls: ['./auth.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class AuthComponent implements OnInit {
|
export class AuthComponent implements OnInit {
|
||||||
keyForm: FormGroup;
|
keyForm: FormGroup;
|
||||||
@ -33,12 +33,16 @@ export class AuthComponent implements OnInit {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
get keyFormStub(): any { return this.keyForm.controls; }
|
get keyFormStub(): any {
|
||||||
|
return this.keyForm.controls;
|
||||||
|
}
|
||||||
|
|
||||||
async onSubmit(): Promise<void> {
|
async onSubmit(): Promise<void> {
|
||||||
this.submitted = true;
|
this.submitted = true;
|
||||||
|
|
||||||
if (this.keyForm.invalid) { return; }
|
if (this.keyForm.invalid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
await this.authService.setKey(this.keyFormStub.key.value);
|
await this.authService.setKey(this.keyFormStub.key.value);
|
||||||
|
@ -11,7 +11,6 @@ import {MatInputModule} from '@angular/material/input';
|
|||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatRippleModule } from '@angular/material/core';
|
import { MatRippleModule } from '@angular/material/core';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [AuthComponent, PasswordToggleDirective],
|
declarations: [AuthComponent, PasswordToggleDirective],
|
||||||
imports: [
|
imports: [
|
||||||
@ -23,6 +22,6 @@ import {MatRippleModule} from '@angular/material/core';
|
|||||||
MatInputModule,
|
MatInputModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatRippleModule,
|
MatRippleModule,
|
||||||
]
|
],
|
||||||
})
|
})
|
||||||
export class AuthModule {}
|
export class AuthModule {}
|
||||||
|
@ -7,7 +7,13 @@ import {ActivatedRoute} from '@angular/router';
|
|||||||
import { AccountsModule } from '@pages/accounts/accounts.module';
|
import { AccountsModule } from '@pages/accounts/accounts.module';
|
||||||
import { UserService } from '@app/_services';
|
import { UserService } from '@app/_services';
|
||||||
import { AppModule } from '@app/app.module';
|
import { AppModule } from '@app/app.module';
|
||||||
import {ActivatedRouteStub, FooterStubComponent, SidebarStubComponent, TopbarStubComponent, UserServiceStub} from '@src/testing';
|
import {
|
||||||
|
ActivatedRouteStub,
|
||||||
|
FooterStubComponent,
|
||||||
|
SidebarStubComponent,
|
||||||
|
TopbarStubComponent,
|
||||||
|
UserServiceStub,
|
||||||
|
} from '@src/testing';
|
||||||
|
|
||||||
describe('AccountDetailsComponent', () => {
|
describe('AccountDetailsComponent', () => {
|
||||||
let component: AccountDetailsComponent;
|
let component: AccountDetailsComponent;
|
||||||
@ -24,19 +30,14 @@ describe('AccountDetailsComponent', () => {
|
|||||||
AccountDetailsComponent,
|
AccountDetailsComponent,
|
||||||
FooterStubComponent,
|
FooterStubComponent,
|
||||||
SidebarStubComponent,
|
SidebarStubComponent,
|
||||||
TopbarStubComponent
|
TopbarStubComponent,
|
||||||
],
|
|
||||||
imports: [
|
|
||||||
AccountsModule,
|
|
||||||
AppModule,
|
|
||||||
HttpClientTestingModule,
|
|
||||||
],
|
],
|
||||||
|
imports: [AccountsModule, AppModule, HttpClientTestingModule],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: ActivatedRoute, useValue: route },
|
{ provide: ActivatedRoute, useValue: route },
|
||||||
{ provide: UserService, useClass: UserServiceStub }
|
{ provide: UserService, useClass: UserServiceStub },
|
||||||
]
|
],
|
||||||
})
|
}).compileComponents();
|
||||||
.compileComponents();
|
|
||||||
httpClient = TestBed.inject(HttpClient);
|
httpClient = TestBed.inject(HttpClient);
|
||||||
httpTestingController = TestBed.inject(HttpTestingController);
|
httpTestingController = TestBed.inject(HttpTestingController);
|
||||||
});
|
});
|
||||||
|
@ -1,8 +1,21 @@
|
|||||||
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit, ViewChild} from '@angular/core';
|
import {
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
ChangeDetectorRef,
|
||||||
|
Component,
|
||||||
|
OnInit,
|
||||||
|
ViewChild,
|
||||||
|
} from '@angular/core';
|
||||||
import { MatTableDataSource } from '@angular/material/table';
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
import { MatPaginator } from '@angular/material/paginator';
|
import { MatPaginator } from '@angular/material/paginator';
|
||||||
import { MatSort } from '@angular/material/sort';
|
import { MatSort } from '@angular/material/sort';
|
||||||
import {BlockSyncService, LocationService, LoggingService, TokenService, TransactionService, UserService} from '@app/_services';
|
import {
|
||||||
|
BlockSyncService,
|
||||||
|
LocationService,
|
||||||
|
LoggingService,
|
||||||
|
TokenService,
|
||||||
|
TransactionService,
|
||||||
|
UserService,
|
||||||
|
} from '@app/_services';
|
||||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||||
import { first } from 'rxjs/operators';
|
import { first } from 'rxjs/operators';
|
||||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
@ -16,7 +29,7 @@ import {AccountDetails, AreaName, AreaType, Category, Transaction} from '@app/_m
|
|||||||
selector: 'app-account-details',
|
selector: 'app-account-details',
|
||||||
templateUrl: './account-details.component.html',
|
templateUrl: './account-details.component.html',
|
||||||
styleUrls: ['./account-details.component.scss'],
|
styleUrls: ['./account-details.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class AccountDetailsComponent implements OnInit {
|
export class AccountDetailsComponent implements OnInit {
|
||||||
transactionsDataSource: MatTableDataSource<any>;
|
transactionsDataSource: MatTableDataSource<any>;
|
||||||
@ -63,7 +76,7 @@ export class AccountDetailsComponent implements OnInit {
|
|||||||
private loggingService: LoggingService,
|
private loggingService: LoggingService,
|
||||||
private blockSyncService: BlockSyncService,
|
private blockSyncService: BlockSyncService,
|
||||||
private cdr: ChangeDetectorRef,
|
private cdr: ChangeDetectorRef,
|
||||||
private snackBar: MatSnackBar,
|
private snackBar: MatSnackBar
|
||||||
) {
|
) {
|
||||||
this.accountInfoForm = this.formBuilder.group({
|
this.accountInfoForm = this.formBuilder.group({
|
||||||
name: ['', Validators.required],
|
name: ['', Validators.required],
|
||||||
@ -79,8 +92,10 @@ export class AccountDetailsComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
this.route.paramMap.subscribe(async (params: Params) => {
|
this.route.paramMap.subscribe(async (params: Params) => {
|
||||||
this.accountAddress = add0x(params.get('id'));
|
this.accountAddress = add0x(params.get('id'));
|
||||||
this.bloxbergLink = 'https://blockexplorer.bloxberg.org/address/' + this.accountAddress + '/transactions';
|
this.bloxbergLink =
|
||||||
(await this.userService.getAccountByAddress(this.accountAddress, 100)).subscribe(async res => {
|
'https://blockexplorer.bloxberg.org/address/' + this.accountAddress + '/transactions';
|
||||||
|
(await this.userService.getAccountByAddress(this.accountAddress, 100)).subscribe(
|
||||||
|
async (res) => {
|
||||||
if (res !== undefined) {
|
if (res !== undefined) {
|
||||||
this.account = res;
|
this.account = res;
|
||||||
this.cdr.detectChanges();
|
this.cdr.detectChanges();
|
||||||
@ -102,26 +117,45 @@ export class AccountDetailsComponent implements OnInit {
|
|||||||
} else {
|
} else {
|
||||||
alert('Account not found!');
|
alert('Account not found!');
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
);
|
||||||
this.blockSyncService.blockSync(this.accountAddress);
|
this.blockSyncService.blockSync(this.accountAddress);
|
||||||
});
|
});
|
||||||
this.userService.getCategories().pipe(first()).subscribe(res => this.categories = res);
|
this.userService
|
||||||
this.locationService.getAreaNames().pipe(first()).subscribe(res => this.areaNames = res);
|
.getCategories()
|
||||||
this.locationService.getAreaTypes().pipe(first()).subscribe(res => this.areaTypes = res);
|
.pipe(first())
|
||||||
this.userService.getAccountTypes().pipe(first()).subscribe(res => this.accountTypes = res);
|
.subscribe((res) => (this.categories = res));
|
||||||
this.userService.getTransactionTypes().pipe(first()).subscribe(res => this.transactionsTypes = res);
|
this.locationService
|
||||||
this.userService.getGenders().pipe(first()).subscribe(res => this.genders = res);
|
.getAreaNames()
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((res) => (this.areaNames = res));
|
||||||
|
this.locationService
|
||||||
|
.getAreaTypes()
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((res) => (this.areaTypes = res));
|
||||||
|
this.userService
|
||||||
|
.getAccountTypes()
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((res) => (this.accountTypes = res));
|
||||||
|
this.userService
|
||||||
|
.getTransactionTypes()
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((res) => (this.transactionsTypes = res));
|
||||||
|
this.userService
|
||||||
|
.getGenders()
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((res) => (this.genders = res));
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.userService.accountsSubject.subscribe(accounts => {
|
this.userService.accountsSubject.subscribe((accounts) => {
|
||||||
this.userDataSource = new MatTableDataSource<any>(accounts);
|
this.userDataSource = new MatTableDataSource<any>(accounts);
|
||||||
this.userDataSource.paginator = this.userTablePaginator;
|
this.userDataSource.paginator = this.userTablePaginator;
|
||||||
this.userDataSource.sort = this.userTableSort;
|
this.userDataSource.sort = this.userTableSort;
|
||||||
this.accounts = accounts;
|
this.accounts = accounts;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.transactionService.transactionsSubject.subscribe(transactions => {
|
this.transactionService.transactionsSubject.subscribe((transactions) => {
|
||||||
this.transactionsDataSource = new MatTableDataSource<any>(transactions);
|
this.transactionsDataSource = new MatTableDataSource<any>(transactions);
|
||||||
this.transactionsDataSource.paginator = this.transactionTablePaginator;
|
this.transactionsDataSource.paginator = this.transactionTablePaginator;
|
||||||
this.transactionsDataSource.sort = this.transactionTableSort;
|
this.transactionsDataSource.sort = this.transactionTableSort;
|
||||||
@ -142,14 +176,20 @@ export class AccountDetailsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
viewAccount(account): void {
|
viewAccount(account): void {
|
||||||
this.router.navigateByUrl(`/accounts/${strip0x(account.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0])}`);
|
this.router.navigateByUrl(
|
||||||
|
`/accounts/${strip0x(account.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0])}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get accountInfoFormStub(): any { return this.accountInfoForm.controls; }
|
get accountInfoFormStub(): any {
|
||||||
|
return this.accountInfoForm.controls;
|
||||||
|
}
|
||||||
|
|
||||||
async saveInfo(): Promise<void> {
|
async saveInfo(): Promise<void> {
|
||||||
this.submitted = true;
|
this.submitted = true;
|
||||||
if (this.accountInfoForm.invalid || !confirm('Change user\'s profile information?')) { return; }
|
if (this.accountInfoForm.invalid || !confirm(`Change user's profile information?`)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const accountKey = await this.userService.changeAccountInfo(
|
const accountKey = await this.userService.changeAccountInfo(
|
||||||
this.accountAddress,
|
this.accountAddress,
|
||||||
this.accountInfoFormStub.name.value,
|
this.accountInfoFormStub.name.value,
|
||||||
@ -168,29 +208,38 @@ export class AccountDetailsComponent implements OnInit {
|
|||||||
|
|
||||||
filterAccounts(): void {
|
filterAccounts(): void {
|
||||||
if (this.accountsType === 'all') {
|
if (this.accountsType === 'all') {
|
||||||
this.userService.accountsSubject.subscribe(accounts => {
|
this.userService.accountsSubject.subscribe((accounts) => {
|
||||||
this.userDataSource.data = accounts;
|
this.userDataSource.data = accounts;
|
||||||
this.accounts = accounts;
|
this.accounts = accounts;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.userDataSource.data = this.accounts.filter(account => account.type === this.accountsType);
|
this.userDataSource.data = this.accounts.filter(
|
||||||
|
(account) => account.type === this.accountsType
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
filterTransactions(): void {
|
filterTransactions(): void {
|
||||||
if (this.transactionsType === 'all') {
|
if (this.transactionsType === 'all') {
|
||||||
this.transactionService.transactionsSubject.subscribe(transactions => {
|
this.transactionService.transactionsSubject.subscribe((transactions) => {
|
||||||
this.transactionsDataSource.data = transactions;
|
this.transactionsDataSource.data = transactions;
|
||||||
this.transactions = transactions;
|
this.transactions = transactions;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.transactionsDataSource.data = this.transactions.filter(transaction => transaction.type === this.transactionsType);
|
this.transactionsDataSource.data = this.transactions.filter(
|
||||||
|
(transaction) => transaction.type === this.transactionsType
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resetPin(): void {
|
resetPin(): void {
|
||||||
if (!confirm('Reset user\'s pin?')) { return; }
|
if (!confirm(`Reset user's pin?`)) {
|
||||||
this.userService.resetPin(this.account.vcard.tel[0].value).pipe(first()).subscribe(res => {
|
return;
|
||||||
|
}
|
||||||
|
this.userService
|
||||||
|
.resetPin(this.account.vcard.tel[0].value)
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((res) => {
|
||||||
this.loggingService.sendInfoLevelMessage(`Response: ${res}`);
|
this.loggingService.sendInfoLevelMessage(`Response: ${res}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -201,7 +250,9 @@ export class AccountDetailsComponent implements OnInit {
|
|||||||
|
|
||||||
copyAddress(): void {
|
copyAddress(): void {
|
||||||
if (copyToClipboard(this.accountAddress)) {
|
if (copyToClipboard(this.accountAddress)) {
|
||||||
this.snackBar.open(this.accountAddress + ' copied successfully!', 'Close', { duration: 3000 });
|
this.snackBar.open(this.accountAddress + ' copied successfully!', 'Close', {
|
||||||
|
duration: 3000,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,8 @@ describe('AccountSearchComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ AccountSearchComponent ]
|
declarations: [AccountSearchComponent],
|
||||||
})
|
}).compileComponents();
|
||||||
.compileComponents();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -10,7 +10,7 @@ import {environment} from '@src/environments/environment';
|
|||||||
selector: 'app-account-search',
|
selector: 'app-account-search',
|
||||||
templateUrl: './account-search.component.html',
|
templateUrl: './account-search.component.html',
|
||||||
styleUrls: ['./account-search.component.scss'],
|
styleUrls: ['./account-search.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class AccountSearchComponent implements OnInit {
|
export class AccountSearchComponent implements OnInit {
|
||||||
nameSearchForm: FormGroup;
|
nameSearchForm: FormGroup;
|
||||||
@ -27,7 +27,7 @@ export class AccountSearchComponent implements OnInit {
|
|||||||
constructor(
|
constructor(
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
private userService: UserService,
|
private userService: UserService,
|
||||||
private router: Router,
|
private router: Router
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
@ -42,13 +42,21 @@ export class AccountSearchComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get nameSearchFormStub(): any { return this.nameSearchForm.controls; }
|
get nameSearchFormStub(): any {
|
||||||
get phoneSearchFormStub(): any { return this.phoneSearchForm.controls; }
|
return this.nameSearchForm.controls;
|
||||||
get addressSearchFormStub(): any { return this.addressSearchForm.controls; }
|
}
|
||||||
|
get phoneSearchFormStub(): any {
|
||||||
|
return this.phoneSearchForm.controls;
|
||||||
|
}
|
||||||
|
get addressSearchFormStub(): any {
|
||||||
|
return this.addressSearchForm.controls;
|
||||||
|
}
|
||||||
|
|
||||||
onNameSearch(): void {
|
onNameSearch(): void {
|
||||||
this.nameSearchSubmitted = true;
|
this.nameSearchSubmitted = true;
|
||||||
if (this.nameSearchForm.invalid) { return; }
|
if (this.nameSearchForm.invalid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.nameSearchLoading = true;
|
this.nameSearchLoading = true;
|
||||||
this.userService.searchAccountByName(this.nameSearchFormStub.name.value);
|
this.userService.searchAccountByName(this.nameSearchFormStub.name.value);
|
||||||
this.nameSearchLoading = false;
|
this.nameSearchLoading = false;
|
||||||
@ -56,11 +64,17 @@ export class AccountSearchComponent implements OnInit {
|
|||||||
|
|
||||||
async onPhoneSearch(): Promise<void> {
|
async onPhoneSearch(): Promise<void> {
|
||||||
this.phoneSearchSubmitted = true;
|
this.phoneSearchSubmitted = true;
|
||||||
if (this.phoneSearchForm.invalid) { return; }
|
if (this.phoneSearchForm.invalid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.phoneSearchLoading = true;
|
this.phoneSearchLoading = true;
|
||||||
(await this.userService.getAccountByPhone(this.phoneSearchFormStub.phoneNumber.value, 100)).subscribe(async res => {
|
(
|
||||||
|
await this.userService.getAccountByPhone(this.phoneSearchFormStub.phoneNumber.value, 100)
|
||||||
|
).subscribe(async (res) => {
|
||||||
if (res !== undefined) {
|
if (res !== undefined) {
|
||||||
await this.router.navigateByUrl(`/accounts/${strip0x(res.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0])}`);
|
await this.router.navigateByUrl(
|
||||||
|
`/accounts/${strip0x(res.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0])}`
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
alert('Account not found!');
|
alert('Account not found!');
|
||||||
}
|
}
|
||||||
@ -70,11 +84,17 @@ export class AccountSearchComponent implements OnInit {
|
|||||||
|
|
||||||
async onAddressSearch(): Promise<void> {
|
async onAddressSearch(): Promise<void> {
|
||||||
this.addressSearchSubmitted = true;
|
this.addressSearchSubmitted = true;
|
||||||
if (this.addressSearchForm.invalid) { return; }
|
if (this.addressSearchForm.invalid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.addressSearchLoading = true;
|
this.addressSearchLoading = true;
|
||||||
(await this.userService.getAccountByAddress(this.addressSearchFormStub.address.value, 100)).subscribe(async res => {
|
(
|
||||||
|
await this.userService.getAccountByAddress(this.addressSearchFormStub.address.value, 100)
|
||||||
|
).subscribe(async (res) => {
|
||||||
if (res !== undefined) {
|
if (res !== undefined) {
|
||||||
await this.router.navigateByUrl(`/accounts/${strip0x(res.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0])}`);
|
await this.router.navigateByUrl(
|
||||||
|
`/accounts/${strip0x(res.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0])}`
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
alert('Account not found!');
|
alert('Account not found!');
|
||||||
}
|
}
|
||||||
|
@ -11,11 +11,11 @@ const routes: Routes = [
|
|||||||
{ path: 'search', component: AccountSearchComponent },
|
{ path: 'search', component: AccountSearchComponent },
|
||||||
// { path: 'create', component: CreateAccountComponent },
|
// { path: 'create', component: CreateAccountComponent },
|
||||||
{ path: ':id', component: AccountDetailsComponent },
|
{ path: ':id', component: AccountDetailsComponent },
|
||||||
{ path: '**', redirectTo: '', pathMatch: 'full' }
|
{ path: '**', redirectTo: '', pathMatch: 'full' },
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forChild(routes)],
|
imports: [RouterModule.forChild(routes)],
|
||||||
exports: [RouterModule]
|
exports: [RouterModule],
|
||||||
})
|
})
|
||||||
export class AccountsRoutingModule {}
|
export class AccountsRoutingModule {}
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { AccountsComponent } from './accounts.component';
|
import { AccountsComponent } from './accounts.component';
|
||||||
import {FooterStubComponent, SidebarStubComponent, TopbarStubComponent, UserServiceStub} from '@src/testing';
|
import {
|
||||||
|
FooterStubComponent,
|
||||||
|
SidebarStubComponent,
|
||||||
|
TopbarStubComponent,
|
||||||
|
UserServiceStub,
|
||||||
|
} from '@src/testing';
|
||||||
import { AccountsModule } from '@pages/accounts/accounts.module';
|
import { AccountsModule } from '@pages/accounts/accounts.module';
|
||||||
import { AppModule } from '@app/app.module';
|
import { AppModule } from '@app/app.module';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
@ -20,18 +25,11 @@ describe('AccountsComponent', () => {
|
|||||||
AccountsComponent,
|
AccountsComponent,
|
||||||
FooterStubComponent,
|
FooterStubComponent,
|
||||||
SidebarStubComponent,
|
SidebarStubComponent,
|
||||||
TopbarStubComponent
|
TopbarStubComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [AccountsModule, AppModule, HttpClientTestingModule],
|
||||||
AccountsModule,
|
providers: [{ provide: UserService, useClass: UserServiceStub }],
|
||||||
AppModule,
|
}).compileComponents();
|
||||||
HttpClientTestingModule,
|
|
||||||
],
|
|
||||||
providers: [
|
|
||||||
{ provide: UserService, useClass: UserServiceStub }
|
|
||||||
]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
httpClient = TestBed.inject(HttpClient);
|
httpClient = TestBed.inject(HttpClient);
|
||||||
httpTestingController = TestBed.inject(HttpTestingController);
|
httpTestingController = TestBed.inject(HttpTestingController);
|
||||||
});
|
});
|
||||||
|
@ -14,7 +14,7 @@ import {AccountDetails} from '@app/_models';
|
|||||||
selector: 'app-accounts',
|
selector: 'app-accounts',
|
||||||
templateUrl: './accounts.component.html',
|
templateUrl: './accounts.component.html',
|
||||||
styleUrls: ['./accounts.component.scss'],
|
styleUrls: ['./accounts.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class AccountsComponent implements OnInit {
|
export class AccountsComponent implements OnInit {
|
||||||
dataSource: MatTableDataSource<any>;
|
dataSource: MatTableDataSource<any>;
|
||||||
@ -32,8 +32,7 @@ export class AccountsComponent implements OnInit {
|
|||||||
private userService: UserService,
|
private userService: UserService,
|
||||||
private loggingService: LoggingService,
|
private loggingService: LoggingService,
|
||||||
private router: Router
|
private router: Router
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
// TODO it feels like this should be in the onInit handler
|
// TODO it feels like this should be in the onInit handler
|
||||||
@ -42,11 +41,14 @@ export class AccountsComponent implements OnInit {
|
|||||||
this.loggingService.sendErrorLevelMessage('Failed to load accounts', this, { error });
|
this.loggingService.sendErrorLevelMessage('Failed to load accounts', this, { error });
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
this.userService.getAccountTypes().pipe(first()).subscribe(res => this.accountTypes = res);
|
this.userService
|
||||||
|
.getAccountTypes()
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((res) => (this.accountTypes = res));
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.userService.accountsSubject.subscribe(accounts => {
|
this.userService.accountsSubject.subscribe((accounts) => {
|
||||||
this.dataSource = new MatTableDataSource<any>(accounts);
|
this.dataSource = new MatTableDataSource<any>(accounts);
|
||||||
this.dataSource.paginator = this.paginator;
|
this.dataSource.paginator = this.paginator;
|
||||||
this.dataSource.sort = this.sort;
|
this.dataSource.sort = this.sort;
|
||||||
@ -59,17 +61,19 @@ export class AccountsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async viewAccount(account): Promise<void> {
|
async viewAccount(account): Promise<void> {
|
||||||
await this.router.navigateByUrl(`/accounts/${strip0x(account.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0])}`);
|
await this.router.navigateByUrl(
|
||||||
|
`/accounts/${strip0x(account.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0])}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
filterAccounts(): void {
|
filterAccounts(): void {
|
||||||
if (this.accountsType === 'all') {
|
if (this.accountsType === 'all') {
|
||||||
this.userService.accountsSubject.subscribe(accounts => {
|
this.userService.accountsSubject.subscribe((accounts) => {
|
||||||
this.dataSource.data = accounts;
|
this.dataSource.data = accounts;
|
||||||
this.accounts = accounts;
|
this.accounts = accounts;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.dataSource.data = this.accounts.filter(account => account.type === this.accountsType);
|
this.dataSource.data = this.accounts.filter((account) => account.type === this.accountsType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,13 +25,12 @@ import {ReactiveFormsModule} from '@angular/forms';
|
|||||||
import { AccountSearchComponent } from './account-search/account-search.component';
|
import { AccountSearchComponent } from './account-search/account-search.component';
|
||||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AccountsComponent,
|
AccountsComponent,
|
||||||
AccountDetailsComponent,
|
AccountDetailsComponent,
|
||||||
CreateAccountComponent,
|
CreateAccountComponent,
|
||||||
AccountSearchComponent
|
AccountSearchComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@ -54,6 +53,6 @@ import {MatSnackBarModule} from '@angular/material/snack-bar';
|
|||||||
MatProgressSpinnerModule,
|
MatProgressSpinnerModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
MatSnackBarModule,
|
MatSnackBarModule,
|
||||||
]
|
],
|
||||||
})
|
})
|
||||||
export class AccountsModule {}
|
export class AccountsModule {}
|
||||||
|
@ -5,7 +5,6 @@ import {AccountsModule} from '@pages/accounts/accounts.module';
|
|||||||
import { AppModule } from '@app/app.module';
|
import { AppModule } from '@app/app.module';
|
||||||
import { FooterStubComponent, SidebarStubComponent, TopbarStubComponent } from '@src/testing';
|
import { FooterStubComponent, SidebarStubComponent, TopbarStubComponent } from '@src/testing';
|
||||||
|
|
||||||
|
|
||||||
describe('CreateAccountComponent', () => {
|
describe('CreateAccountComponent', () => {
|
||||||
let component: CreateAccountComponent;
|
let component: CreateAccountComponent;
|
||||||
let fixture: ComponentFixture<CreateAccountComponent>;
|
let fixture: ComponentFixture<CreateAccountComponent>;
|
||||||
@ -16,14 +15,10 @@ describe('CreateAccountComponent', () => {
|
|||||||
CreateAccountComponent,
|
CreateAccountComponent,
|
||||||
FooterStubComponent,
|
FooterStubComponent,
|
||||||
SidebarStubComponent,
|
SidebarStubComponent,
|
||||||
TopbarStubComponent
|
TopbarStubComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [AccountsModule, AppModule],
|
||||||
AccountsModule,
|
}).compileComponents();
|
||||||
AppModule
|
|
||||||
]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -9,7 +9,7 @@ import {AreaName, Category} from '@app/_models';
|
|||||||
selector: 'app-create-account',
|
selector: 'app-create-account',
|
||||||
templateUrl: './create-account.component.html',
|
templateUrl: './create-account.component.html',
|
||||||
styleUrls: ['./create-account.component.scss'],
|
styleUrls: ['./create-account.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class CreateAccountComponent implements OnInit {
|
export class CreateAccountComponent implements OnInit {
|
||||||
createForm: FormGroup;
|
createForm: FormGroup;
|
||||||
@ -37,19 +37,35 @@ export class CreateAccountComponent implements OnInit {
|
|||||||
location: ['', Validators.required],
|
location: ['', Validators.required],
|
||||||
gender: ['', Validators.required],
|
gender: ['', Validators.required],
|
||||||
referrer: ['', Validators.required],
|
referrer: ['', Validators.required],
|
||||||
businessCategory: ['', Validators.required]
|
businessCategory: ['', Validators.required],
|
||||||
});
|
});
|
||||||
this.userService.getCategories().pipe(first()).subscribe(res => this.categories = res);
|
this.userService
|
||||||
this.locationService.getAreaNames().pipe(first()).subscribe(res => this.areaNames = res);
|
.getCategories()
|
||||||
this.userService.getAccountTypes().pipe(first()).subscribe(res => this.accountTypes = res);
|
.pipe(first())
|
||||||
this.userService.getGenders().pipe(first()).subscribe(res => this.genders = res);
|
.subscribe((res) => (this.categories = res));
|
||||||
|
this.locationService
|
||||||
|
.getAreaNames()
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((res) => (this.areaNames = res));
|
||||||
|
this.userService
|
||||||
|
.getAccountTypes()
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((res) => (this.accountTypes = res));
|
||||||
|
this.userService
|
||||||
|
.getGenders()
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((res) => (this.genders = res));
|
||||||
}
|
}
|
||||||
|
|
||||||
get createFormStub(): any { return this.createForm.controls; }
|
get createFormStub(): any {
|
||||||
|
return this.createForm.controls;
|
||||||
|
}
|
||||||
|
|
||||||
onSubmit(): void {
|
onSubmit(): void {
|
||||||
this.submitted = true;
|
this.submitted = true;
|
||||||
if (this.createForm.invalid || !confirm('Create account?')) { return; }
|
if (this.createForm.invalid || !confirm('Create account?')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.submitted = false;
|
this.submitted = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,6 @@ const routes: Routes = [{ path: '', component: AdminComponent }];
|
|||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forChild(routes)],
|
imports: [RouterModule.forChild(routes)],
|
||||||
exports: [RouterModule]
|
exports: [RouterModule],
|
||||||
})
|
})
|
||||||
export class AdminRoutingModule {}
|
export class AdminRoutingModule {}
|
||||||
|
@ -4,7 +4,12 @@ import { AdminComponent } from '@pages/admin/admin.component';
|
|||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
|
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
|
||||||
import { AdminModule } from '@pages/admin/admin.module';
|
import { AdminModule } from '@pages/admin/admin.module';
|
||||||
import {FooterStubComponent, SidebarStubComponent, TopbarStubComponent, UserServiceStub} from '@src/testing';
|
import {
|
||||||
|
FooterStubComponent,
|
||||||
|
SidebarStubComponent,
|
||||||
|
TopbarStubComponent,
|
||||||
|
UserServiceStub,
|
||||||
|
} from '@src/testing';
|
||||||
import { AppModule } from '@app/app.module';
|
import { AppModule } from '@app/app.module';
|
||||||
import { UserService } from '@app/_services';
|
import { UserService } from '@app/_services';
|
||||||
|
|
||||||
@ -21,18 +26,11 @@ describe('AdminComponent', () => {
|
|||||||
AdminComponent,
|
AdminComponent,
|
||||||
FooterStubComponent,
|
FooterStubComponent,
|
||||||
SidebarStubComponent,
|
SidebarStubComponent,
|
||||||
TopbarStubComponent
|
TopbarStubComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [AdminModule, AppModule, HttpClientTestingModule],
|
||||||
AdminModule,
|
providers: [{ provide: UserService, useClass: UserServiceStub }],
|
||||||
AppModule,
|
}).compileComponents();
|
||||||
HttpClientTestingModule,
|
|
||||||
],
|
|
||||||
providers: [
|
|
||||||
{ provide: UserService, useClass: UserServiceStub }
|
|
||||||
]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
httpClient = TestBed.inject(HttpClient);
|
httpClient = TestBed.inject(HttpClient);
|
||||||
httpTestingController = TestBed.inject(HttpTestingController);
|
httpTestingController = TestBed.inject(HttpTestingController);
|
||||||
userService = new UserServiceStub();
|
userService = new UserServiceStub();
|
||||||
@ -55,7 +53,7 @@ describe('AdminComponent', () => {
|
|||||||
user: 'Tom',
|
user: 'Tom',
|
||||||
role: 'enroller',
|
role: 'enroller',
|
||||||
action: 'Disburse RSV 100',
|
action: 'Disburse RSV 100',
|
||||||
approval: false
|
approval: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -18,8 +18,8 @@ import {Action} from '../../_models';
|
|||||||
state('collapsed', style({ height: '0px', minHeight: 0, visibility: 'hidden' })),
|
state('collapsed', style({ height: '0px', minHeight: 0, visibility: 'hidden' })),
|
||||||
state('expanded', style({ height: '*', visibility: 'visible' })),
|
state('expanded', style({ height: '*', visibility: 'visible' })),
|
||||||
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
|
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
|
||||||
])
|
]),
|
||||||
]
|
],
|
||||||
})
|
})
|
||||||
export class AdminComponent implements OnInit {
|
export class AdminComponent implements OnInit {
|
||||||
dataSource: MatTableDataSource<any>;
|
dataSource: MatTableDataSource<any>;
|
||||||
@ -30,12 +30,9 @@ export class AdminComponent implements OnInit {
|
|||||||
@ViewChild(MatPaginator) paginator: MatPaginator;
|
@ViewChild(MatPaginator) paginator: MatPaginator;
|
||||||
@ViewChild(MatSort) sort: MatSort;
|
@ViewChild(MatSort) sort: MatSort;
|
||||||
|
|
||||||
constructor(
|
constructor(private userService: UserService, private loggingService: LoggingService) {
|
||||||
private userService: UserService,
|
|
||||||
private loggingService: LoggingService
|
|
||||||
) {
|
|
||||||
this.userService.getActions();
|
this.userService.getActions();
|
||||||
this.userService.actionsSubject.subscribe(actions => {
|
this.userService.actionsSubject.subscribe((actions) => {
|
||||||
this.dataSource = new MatTableDataSource<any>(actions);
|
this.dataSource = new MatTableDataSource<any>(actions);
|
||||||
this.dataSource.paginator = this.paginator;
|
this.dataSource.paginator = this.paginator;
|
||||||
this.dataSource.sort = this.sort;
|
this.dataSource.sort = this.sort;
|
||||||
@ -43,8 +40,7 @@ export class AdminComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {}
|
||||||
}
|
|
||||||
|
|
||||||
doFilter(value: string): void {
|
doFilter(value: string): void {
|
||||||
this.dataSource.filter = value.trim().toLocaleLowerCase();
|
this.dataSource.filter = value.trim().toLocaleLowerCase();
|
||||||
@ -55,14 +51,24 @@ export class AdminComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
approveAction(action: any): void {
|
approveAction(action: any): void {
|
||||||
if (!confirm('Approve action?')) { return; }
|
if (!confirm('Approve action?')) {
|
||||||
this.userService.approveAction(action.id).pipe(first()).subscribe(res => this.loggingService.sendInfoLevelMessage(res));
|
return;
|
||||||
|
}
|
||||||
|
this.userService
|
||||||
|
.approveAction(action.id)
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((res) => this.loggingService.sendInfoLevelMessage(res));
|
||||||
this.userService.getActions();
|
this.userService.getActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
disapproveAction(action: any): void {
|
disapproveAction(action: any): void {
|
||||||
if (!confirm('Disapprove action?')) { return; }
|
if (!confirm('Disapprove action?')) {
|
||||||
this.userService.revokeAction(action.id).pipe(first()).subscribe(res => this.loggingService.sendInfoLevelMessage(res));
|
return;
|
||||||
|
}
|
||||||
|
this.userService
|
||||||
|
.revokeAction(action.id)
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((res) => this.loggingService.sendInfoLevelMessage(res));
|
||||||
this.userService.getActions();
|
this.userService.getActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ import {MatPaginatorModule} from '@angular/material/paginator';
|
|||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatRippleModule } from '@angular/material/core';
|
import { MatRippleModule } from '@angular/material/core';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [AdminComponent],
|
declarations: [AdminComponent],
|
||||||
imports: [
|
imports: [
|
||||||
@ -29,7 +28,7 @@ import {MatRippleModule} from '@angular/material/core';
|
|||||||
MatSortModule,
|
MatSortModule,
|
||||||
MatPaginatorModule,
|
MatPaginatorModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatRippleModule
|
MatRippleModule,
|
||||||
]
|
],
|
||||||
})
|
})
|
||||||
export class AdminModule {}
|
export class AdminModule {}
|
||||||
|
@ -5,16 +5,32 @@ import { PagesComponent } from './pages.component';
|
|||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{ path: 'home', component: PagesComponent },
|
{ path: 'home', component: PagesComponent },
|
||||||
{ path: 'tx', loadChildren: () => import('@pages/transactions/transactions.module').then(m => m.TransactionsModule) },
|
{
|
||||||
{ path: 'settings', loadChildren: () => import('@pages/settings/settings.module').then(m => m.SettingsModule) },
|
path: 'tx',
|
||||||
{ path: 'accounts', loadChildren: () => import('@pages/accounts/accounts.module').then(m => m.AccountsModule) },
|
loadChildren: () =>
|
||||||
{ path: 'tokens', loadChildren: () => import('@pages/tokens/tokens.module').then(m => m.TokensModule) },
|
import('@pages/transactions/transactions.module').then((m) => m.TransactionsModule),
|
||||||
{ path: 'admin', loadChildren: () => import('@pages/admin/admin.module').then(m => m.AdminModule) },
|
},
|
||||||
{ path: '**', redirectTo: 'home', pathMatch: 'full'}
|
{
|
||||||
|
path: 'settings',
|
||||||
|
loadChildren: () => import('@pages/settings/settings.module').then((m) => m.SettingsModule),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'accounts',
|
||||||
|
loadChildren: () => import('@pages/accounts/accounts.module').then((m) => m.AccountsModule),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'tokens',
|
||||||
|
loadChildren: () => import('@pages/tokens/tokens.module').then((m) => m.TokensModule),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'admin',
|
||||||
|
loadChildren: () => import('@pages/admin/admin.module').then((m) => m.AdminModule),
|
||||||
|
},
|
||||||
|
{ path: '**', redirectTo: 'home', pathMatch: 'full' },
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forChild(routes)],
|
imports: [RouterModule.forChild(routes)],
|
||||||
exports: [RouterModule]
|
exports: [RouterModule],
|
||||||
})
|
})
|
||||||
export class PagesRoutingModule {}
|
export class PagesRoutingModule {}
|
||||||
|
@ -8,9 +8,8 @@ describe('PagesComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ PagesComponent ]
|
declarations: [PagesComponent],
|
||||||
})
|
}).compileComponents();
|
||||||
.compileComponents();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -4,7 +4,7 @@ import {ChangeDetectionStrategy, Component} from '@angular/core';
|
|||||||
selector: 'app-pages',
|
selector: 'app-pages',
|
||||||
templateUrl: './pages.component.html',
|
templateUrl: './pages.component.html',
|
||||||
styleUrls: ['./pages.component.scss'],
|
styleUrls: ['./pages.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class PagesComponent {
|
export class PagesComponent {
|
||||||
url: string = 'https://dashboard.sarafu.network/';
|
url: string = 'https://dashboard.sarafu.network/';
|
||||||
|
@ -11,7 +11,6 @@ import {MatSelectModule} from '@angular/material/select';
|
|||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatCardModule } from '@angular/material/card';
|
import { MatCardModule } from '@angular/material/card';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [PagesComponent],
|
declarations: [PagesComponent],
|
||||||
imports: [
|
imports: [
|
||||||
@ -23,7 +22,7 @@ import {MatCardModule} from '@angular/material/card';
|
|||||||
MatFormFieldModule,
|
MatFormFieldModule,
|
||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
MatInputModule,
|
MatInputModule,
|
||||||
MatCardModule
|
MatCardModule,
|
||||||
]
|
],
|
||||||
})
|
})
|
||||||
export class PagesModule {}
|
export class PagesModule {}
|
||||||
|
@ -15,14 +15,10 @@ describe('OrganizationComponent', () => {
|
|||||||
OrganizationComponent,
|
OrganizationComponent,
|
||||||
FooterStubComponent,
|
FooterStubComponent,
|
||||||
SidebarStubComponent,
|
SidebarStubComponent,
|
||||||
TopbarStubComponent
|
TopbarStubComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [AppModule, SettingsModule],
|
||||||
AppModule,
|
}).compileComponents();
|
||||||
SettingsModule,
|
|
||||||
]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -6,30 +6,32 @@ import {CustomErrorStateMatcher} from '@app/_helpers';
|
|||||||
selector: 'app-organization',
|
selector: 'app-organization',
|
||||||
templateUrl: './organization.component.html',
|
templateUrl: './organization.component.html',
|
||||||
styleUrls: ['./organization.component.scss'],
|
styleUrls: ['./organization.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class OrganizationComponent implements OnInit {
|
export class OrganizationComponent implements OnInit {
|
||||||
organizationForm: FormGroup;
|
organizationForm: FormGroup;
|
||||||
submitted: boolean = false;
|
submitted: boolean = false;
|
||||||
matcher: CustomErrorStateMatcher = new CustomErrorStateMatcher();
|
matcher: CustomErrorStateMatcher = new CustomErrorStateMatcher();
|
||||||
|
|
||||||
constructor(
|
constructor(private formBuilder: FormBuilder) {}
|
||||||
private formBuilder: FormBuilder
|
|
||||||
) { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.organizationForm = this.formBuilder.group({
|
this.organizationForm = this.formBuilder.group({
|
||||||
disbursement: ['', Validators.required],
|
disbursement: ['', Validators.required],
|
||||||
transfer: '',
|
transfer: '',
|
||||||
countryCode: ['', Validators.required]
|
countryCode: ['', Validators.required],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get organizationFormStub(): any { return this.organizationForm.controls; }
|
get organizationFormStub(): any {
|
||||||
|
return this.organizationForm.controls;
|
||||||
|
}
|
||||||
|
|
||||||
onSubmit(): void {
|
onSubmit(): void {
|
||||||
this.submitted = true;
|
this.submitted = true;
|
||||||
if (this.organizationForm.invalid || !confirm('Set organization information?')) { return; }
|
if (this.organizationForm.invalid || !confirm('Set organization information?')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.submitted = false;
|
this.submitted = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,11 @@ import {OrganizationComponent} from '@pages/settings/organization/organization.c
|
|||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{ path: '', component: SettingsComponent },
|
{ path: '', component: SettingsComponent },
|
||||||
{ path: 'organization', component: OrganizationComponent },
|
{ path: 'organization', component: OrganizationComponent },
|
||||||
{ path: '**', redirectTo: '', pathMatch: 'full' }
|
{ path: '**', redirectTo: '', pathMatch: 'full' },
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forChild(routes)],
|
imports: [RouterModule.forChild(routes)],
|
||||||
exports: [RouterModule]
|
exports: [RouterModule],
|
||||||
})
|
})
|
||||||
export class SettingsRoutingModule {}
|
export class SettingsRoutingModule {}
|
||||||
|
@ -15,14 +15,10 @@ describe('SettingsComponent', () => {
|
|||||||
SettingsComponent,
|
SettingsComponent,
|
||||||
FooterStubComponent,
|
FooterStubComponent,
|
||||||
SidebarStubComponent,
|
SidebarStubComponent,
|
||||||
TopbarStubComponent
|
TopbarStubComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [AppModule, SettingsModule],
|
||||||
AppModule,
|
}).compileComponents();
|
||||||
SettingsModule,
|
|
||||||
]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -10,7 +10,7 @@ import {exportCsv} from '@app/_helpers';
|
|||||||
selector: 'app-settings',
|
selector: 'app-settings',
|
||||||
templateUrl: './settings.component.html',
|
templateUrl: './settings.component.html',
|
||||||
styleUrls: ['./settings.component.scss'],
|
styleUrls: ['./settings.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class SettingsComponent implements OnInit {
|
export class SettingsComponent implements OnInit {
|
||||||
date: string;
|
date: string;
|
||||||
@ -21,9 +21,7 @@ export class SettingsComponent implements OnInit {
|
|||||||
@ViewChild(MatPaginator) paginator: MatPaginator;
|
@ViewChild(MatPaginator) paginator: MatPaginator;
|
||||||
@ViewChild(MatSort) sort: MatSort;
|
@ViewChild(MatSort) sort: MatSort;
|
||||||
|
|
||||||
constructor(
|
constructor(private authService: AuthService) {}
|
||||||
private authService: AuthService
|
|
||||||
) { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
const d = new Date();
|
const d = new Date();
|
||||||
|
@ -19,7 +19,6 @@ import {MatSelectModule} from '@angular/material/select';
|
|||||||
import { MatMenuModule } from '@angular/material/menu';
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [SettingsComponent, OrganizationComponent],
|
declarations: [SettingsComponent, OrganizationComponent],
|
||||||
imports: [
|
imports: [
|
||||||
@ -38,7 +37,7 @@ import {ReactiveFormsModule} from '@angular/forms';
|
|||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
MatMenuModule,
|
MatMenuModule,
|
||||||
ReactiveFormsModule
|
ReactiveFormsModule,
|
||||||
]
|
],
|
||||||
})
|
})
|
||||||
export class SettingsModule {}
|
export class SettingsModule {}
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { TokenDetailsComponent } from '@pages/tokens/token-details/token-details.component';
|
import { TokenDetailsComponent } from '@pages/tokens/token-details/token-details.component';
|
||||||
import {ActivatedRouteStub, FooterStubComponent, SidebarStubComponent, TokenServiceStub, TopbarStubComponent} from '@src/testing';
|
import {
|
||||||
|
ActivatedRouteStub,
|
||||||
|
FooterStubComponent,
|
||||||
|
SidebarStubComponent,
|
||||||
|
TokenServiceStub,
|
||||||
|
TopbarStubComponent,
|
||||||
|
} from '@src/testing';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { TokenService } from '@app/_services';
|
import { TokenService } from '@app/_services';
|
||||||
import { TokensModule } from '@pages/tokens/tokens.module';
|
import { TokensModule } from '@pages/tokens/tokens.module';
|
||||||
@ -20,18 +26,14 @@ describe('TokenDetailsComponent', () => {
|
|||||||
TokenDetailsComponent,
|
TokenDetailsComponent,
|
||||||
FooterStubComponent,
|
FooterStubComponent,
|
||||||
SidebarStubComponent,
|
SidebarStubComponent,
|
||||||
TopbarStubComponent
|
TopbarStubComponent,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: ActivatedRoute, useValue: route },
|
{ provide: ActivatedRoute, useValue: route },
|
||||||
{ provide: TokenService, useClass: TokenServiceStub }
|
{ provide: TokenService, useClass: TokenServiceStub },
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [AppModule, TokensModule],
|
||||||
AppModule,
|
}).compileComponents();
|
||||||
TokensModule,
|
|
||||||
]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -8,23 +8,21 @@ import {Token} from '../../../_models';
|
|||||||
selector: 'app-token-details',
|
selector: 'app-token-details',
|
||||||
templateUrl: './token-details.component.html',
|
templateUrl: './token-details.component.html',
|
||||||
styleUrls: ['./token-details.component.scss'],
|
styleUrls: ['./token-details.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class TokenDetailsComponent implements OnInit {
|
export class TokenDetailsComponent implements OnInit {
|
||||||
token: Token;
|
token: Token;
|
||||||
|
|
||||||
constructor(
|
constructor(private route: ActivatedRoute, private tokenService: TokenService) {
|
||||||
private route: ActivatedRoute,
|
|
||||||
private tokenService: TokenService
|
|
||||||
) {
|
|
||||||
this.route.paramMap.subscribe((params: Params) => {
|
this.route.paramMap.subscribe((params: Params) => {
|
||||||
this.tokenService.getTokenBySymbol(params.get('id')).pipe(first()).subscribe(res => {
|
this.tokenService
|
||||||
|
.getTokenBySymbol(params.get('id'))
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((res) => {
|
||||||
this.token = res;
|
this.token = res;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,6 @@ const routes: Routes = [
|
|||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forChild(routes)],
|
imports: [RouterModule.forChild(routes)],
|
||||||
exports: [RouterModule]
|
exports: [RouterModule],
|
||||||
})
|
})
|
||||||
export class TokensRoutingModule {}
|
export class TokensRoutingModule {}
|
||||||
|
@ -15,14 +15,10 @@ describe('TokensComponent', () => {
|
|||||||
TokensComponent,
|
TokensComponent,
|
||||||
FooterStubComponent,
|
FooterStubComponent,
|
||||||
SidebarStubComponent,
|
SidebarStubComponent,
|
||||||
TopbarStubComponent
|
TopbarStubComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [AppModule, TokensModule],
|
||||||
AppModule,
|
}).compileComponents();
|
||||||
TokensModule
|
|
||||||
]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -12,7 +12,7 @@ import {Token} from '../../_models';
|
|||||||
selector: 'app-tokens',
|
selector: 'app-tokens',
|
||||||
templateUrl: './tokens.component.html',
|
templateUrl: './tokens.component.html',
|
||||||
styleUrls: ['./tokens.component.scss'],
|
styleUrls: ['./tokens.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class TokensComponent implements OnInit {
|
export class TokensComponent implements OnInit {
|
||||||
dataSource: MatTableDataSource<any>;
|
dataSource: MatTableDataSource<any>;
|
||||||
|
@ -18,7 +18,6 @@ import {MatButtonModule} from '@angular/material/button';
|
|||||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||||
import { MatCardModule } from '@angular/material/card';
|
import { MatCardModule } from '@angular/material/card';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [TokensComponent, TokenDetailsComponent],
|
declarations: [TokensComponent, TokenDetailsComponent],
|
||||||
imports: [
|
imports: [
|
||||||
@ -37,7 +36,7 @@ import {MatCardModule} from '@angular/material/card';
|
|||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatToolbarModule,
|
MatToolbarModule,
|
||||||
MatCardModule,
|
MatCardModule,
|
||||||
MatRippleModule
|
MatRippleModule,
|
||||||
]
|
],
|
||||||
})
|
})
|
||||||
export class TokensModule {}
|
export class TokensModule {}
|
||||||
|
@ -8,9 +8,8 @@ describe('TransactionDetailsComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ TransactionDetailsComponent ]
|
declarations: [TransactionDetailsComponent],
|
||||||
})
|
}).compileComponents();
|
||||||
.compileComponents();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -9,7 +9,7 @@ import {strip0x} from '@src/assets/js/ethtx/dist/hex';
|
|||||||
selector: 'app-transaction-details',
|
selector: 'app-transaction-details',
|
||||||
templateUrl: './transaction-details.component.html',
|
templateUrl: './transaction-details.component.html',
|
||||||
styleUrls: ['./transaction-details.component.scss'],
|
styleUrls: ['./transaction-details.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class TransactionDetailsComponent implements OnInit {
|
export class TransactionDetailsComponent implements OnInit {
|
||||||
@Input() transaction;
|
@Input() transaction;
|
||||||
@ -20,15 +20,18 @@ export class TransactionDetailsComponent implements OnInit {
|
|||||||
constructor(
|
constructor(
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private transactionService: TransactionService,
|
private transactionService: TransactionService,
|
||||||
private snackBar: MatSnackBar,
|
private snackBar: MatSnackBar
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
if (this.transaction?.type === 'conversion') {
|
if (this.transaction?.type === 'conversion') {
|
||||||
this.traderBloxbergLink = 'https://blockexplorer.bloxberg.org/address/' + this.transaction?.trader + '/transactions';
|
this.traderBloxbergLink =
|
||||||
|
'https://blockexplorer.bloxberg.org/address/' + this.transaction?.trader + '/transactions';
|
||||||
} else {
|
} else {
|
||||||
this.senderBloxbergLink = 'https://blockexplorer.bloxberg.org/address/' + this.transaction?.from + '/transactions';
|
this.senderBloxbergLink =
|
||||||
this.recipientBloxbergLink = 'https://blockexplorer.bloxberg.org/address/' + this.transaction?.to + '/transactions';
|
'https://blockexplorer.bloxberg.org/address/' + this.transaction?.from + '/transactions';
|
||||||
|
this.recipientBloxbergLink =
|
||||||
|
'https://blockexplorer.bloxberg.org/address/' + this.transaction?.to + '/transactions';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,6 @@ const routes: Routes = [{ path: '', component: TransactionsComponent }];
|
|||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forChild(routes)],
|
imports: [RouterModule.forChild(routes)],
|
||||||
exports: [RouterModule]
|
exports: [RouterModule],
|
||||||
})
|
})
|
||||||
export class TransactionsRoutingModule {}
|
export class TransactionsRoutingModule {}
|
||||||
|
@ -19,15 +19,10 @@ describe('TransactionsComponent', () => {
|
|||||||
TransactionsComponent,
|
TransactionsComponent,
|
||||||
FooterStubComponent,
|
FooterStubComponent,
|
||||||
SidebarStubComponent,
|
SidebarStubComponent,
|
||||||
TopbarStubComponent
|
TopbarStubComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [AppModule, HttpClientTestingModule, TransactionsModule],
|
||||||
AppModule,
|
}).compileComponents();
|
||||||
HttpClientTestingModule,
|
|
||||||
TransactionsModule
|
|
||||||
]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
httpClient = TestBed.inject(HttpClient);
|
httpClient = TestBed.inject(HttpClient);
|
||||||
httpTestingController = TestBed.inject(HttpTestingController);
|
httpTestingController = TestBed.inject(HttpTestingController);
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
import {AfterViewInit, ChangeDetectionStrategy, Component, OnInit, ViewChild} from '@angular/core';
|
import {
|
||||||
|
AfterViewInit,
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
Component,
|
||||||
|
OnInit,
|
||||||
|
ViewChild,
|
||||||
|
} from '@angular/core';
|
||||||
import { BlockSyncService, TransactionService, UserService } from '@app/_services';
|
import { BlockSyncService, TransactionService, UserService } from '@app/_services';
|
||||||
import { MatTableDataSource } from '@angular/material/table';
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
import { MatPaginator } from '@angular/material/paginator';
|
import { MatPaginator } from '@angular/material/paginator';
|
||||||
@ -11,7 +17,7 @@ import {Transaction} from '@app/_models';
|
|||||||
selector: 'app-transactions',
|
selector: 'app-transactions',
|
||||||
templateUrl: './transactions.component.html',
|
templateUrl: './transactions.component.html',
|
||||||
styleUrls: ['./transactions.component.scss'],
|
styleUrls: ['./transactions.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class TransactionsComponent implements OnInit, AfterViewInit {
|
export class TransactionsComponent implements OnInit, AfterViewInit {
|
||||||
transactionDataSource: MatTableDataSource<any>;
|
transactionDataSource: MatTableDataSource<any>;
|
||||||
@ -35,13 +41,16 @@ export class TransactionsComponent implements OnInit, AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.transactionService.transactionsSubject.subscribe(transactions => {
|
this.transactionService.transactionsSubject.subscribe((transactions) => {
|
||||||
this.transactionDataSource = new MatTableDataSource<any>(transactions);
|
this.transactionDataSource = new MatTableDataSource<any>(transactions);
|
||||||
this.transactionDataSource.paginator = this.paginator;
|
this.transactionDataSource.paginator = this.paginator;
|
||||||
this.transactionDataSource.sort = this.sort;
|
this.transactionDataSource.sort = this.sort;
|
||||||
this.transactions = transactions;
|
this.transactions = transactions;
|
||||||
});
|
});
|
||||||
this.userService.getTransactionTypes().pipe(first()).subscribe(res => this.transactionsTypes = res);
|
this.userService
|
||||||
|
.getTransactionTypes()
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe((res) => (this.transactionsTypes = res));
|
||||||
}
|
}
|
||||||
|
|
||||||
viewTransaction(transaction): void {
|
viewTransaction(transaction): void {
|
||||||
@ -54,12 +63,14 @@ export class TransactionsComponent implements OnInit, AfterViewInit {
|
|||||||
|
|
||||||
filterTransactions(): void {
|
filterTransactions(): void {
|
||||||
if (this.transactionsType === 'all') {
|
if (this.transactionsType === 'all') {
|
||||||
this.transactionService.transactionsSubject.subscribe(transactions => {
|
this.transactionService.transactionsSubject.subscribe((transactions) => {
|
||||||
this.transactionDataSource.data = transactions;
|
this.transactionDataSource.data = transactions;
|
||||||
this.transactions = transactions;
|
this.transactions = transactions;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.transactionDataSource.data = this.transactions.filter(transaction => transaction.type === this.transactionsType);
|
this.transactionDataSource.data = this.transactions.filter(
|
||||||
|
(transaction) => transaction.type === this.transactionsType
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,12 +19,9 @@ import {MatCardModule} from '@angular/material/card';
|
|||||||
import { MatRippleModule } from '@angular/material/core';
|
import { MatRippleModule } from '@angular/material/core';
|
||||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [TransactionsComponent, TransactionDetailsComponent],
|
declarations: [TransactionsComponent, TransactionDetailsComponent],
|
||||||
exports: [
|
exports: [TransactionDetailsComponent],
|
||||||
TransactionDetailsComponent
|
|
||||||
],
|
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
TransactionsRoutingModule,
|
TransactionsRoutingModule,
|
||||||
@ -42,6 +39,6 @@ import {MatSnackBarModule} from '@angular/material/snack-bar';
|
|||||||
MatCardModule,
|
MatCardModule,
|
||||||
MatRippleModule,
|
MatRippleModule,
|
||||||
MatSnackBarModule,
|
MatSnackBarModule,
|
||||||
]
|
],
|
||||||
})
|
})
|
||||||
export class TransactionsModule {}
|
export class TransactionsModule {}
|
||||||
|
@ -2,7 +2,9 @@ import { MenuSelectionDirective } from '@app/shared/_directives/menu-selection.d
|
|||||||
import { ElementRef, Renderer2 } from '@angular/core';
|
import { ElementRef, Renderer2 } from '@angular/core';
|
||||||
|
|
||||||
describe('MenuSelectionDirective', () => {
|
describe('MenuSelectionDirective', () => {
|
||||||
|
// tslint:disable-next-line:prefer-const
|
||||||
let elementRef: ElementRef;
|
let elementRef: ElementRef;
|
||||||
|
// tslint:disable-next-line:prefer-const
|
||||||
let renderer: Renderer2;
|
let renderer: Renderer2;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
import { Directive, ElementRef, Renderer2 } from '@angular/core';
|
import { Directive, ElementRef, Renderer2 } from '@angular/core';
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: '[appMenuSelection]'
|
selector: '[appMenuSelection]',
|
||||||
})
|
})
|
||||||
export class MenuSelectionDirective {
|
export class MenuSelectionDirective {
|
||||||
|
constructor(private elementRef: ElementRef, private renderer: Renderer2) {
|
||||||
constructor(
|
|
||||||
private elementRef: ElementRef,
|
|
||||||
private renderer: Renderer2
|
|
||||||
) {
|
|
||||||
this.renderer.listen(this.elementRef.nativeElement, 'click', () => {
|
this.renderer.listen(this.elementRef.nativeElement, 'click', () => {
|
||||||
const mediaQuery = window.matchMedia('(max-width: 768px)');
|
const mediaQuery = window.matchMedia('(max-width: 768px)');
|
||||||
if (mediaQuery.matches) {
|
if (mediaQuery.matches) {
|
||||||
|
@ -2,7 +2,9 @@ import { MenuToggleDirective } from '@app/shared/_directives/menu-toggle.directi
|
|||||||
import { ElementRef, Renderer2 } from '@angular/core';
|
import { ElementRef, Renderer2 } from '@angular/core';
|
||||||
|
|
||||||
describe('MenuToggleDirective', () => {
|
describe('MenuToggleDirective', () => {
|
||||||
|
// tslint:disable-next-line:prefer-const
|
||||||
let elementRef: ElementRef;
|
let elementRef: ElementRef;
|
||||||
|
// tslint:disable-next-line:prefer-const
|
||||||
let renderer: Renderer2;
|
let renderer: Renderer2;
|
||||||
it('should create an instance', () => {
|
it('should create an instance', () => {
|
||||||
const directive = new MenuToggleDirective(elementRef, renderer);
|
const directive = new MenuToggleDirective(elementRef, renderer);
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
import { Directive, ElementRef, Renderer2 } from '@angular/core';
|
import { Directive, ElementRef, Renderer2 } from '@angular/core';
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: '[appMenuToggle]'
|
selector: '[appMenuToggle]',
|
||||||
})
|
})
|
||||||
export class MenuToggleDirective {
|
export class MenuToggleDirective {
|
||||||
|
constructor(private elementRef: ElementRef, private renderer: Renderer2) {
|
||||||
constructor(
|
|
||||||
private elementRef: ElementRef,
|
|
||||||
private renderer: Renderer2
|
|
||||||
) {
|
|
||||||
this.renderer.listen(this.elementRef.nativeElement, 'click', () => {
|
this.renderer.listen(this.elementRef.nativeElement, 'click', () => {
|
||||||
this.onMenuToggle();
|
this.onMenuToggle();
|
||||||
});
|
});
|
||||||
|
@ -2,14 +2,12 @@ import { Pipe, PipeTransform } from '@angular/core';
|
|||||||
import { DomSanitizer } from '@angular/platform-browser';
|
import { DomSanitizer } from '@angular/platform-browser';
|
||||||
|
|
||||||
@Pipe({
|
@Pipe({
|
||||||
name: 'safe'
|
name: 'safe',
|
||||||
})
|
})
|
||||||
export class SafePipe implements PipeTransform {
|
export class SafePipe implements PipeTransform {
|
||||||
|
|
||||||
constructor(private sanitizer: DomSanitizer) {}
|
constructor(private sanitizer: DomSanitizer) {}
|
||||||
|
|
||||||
transform(url: string, ...args: unknown[]): unknown {
|
transform(url: string, ...args: unknown[]): unknown {
|
||||||
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
|
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,8 @@ describe('ErrorDialogComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ ErrorDialogComponent ]
|
declarations: [ErrorDialogComponent],
|
||||||
})
|
}).compileComponents();
|
||||||
.compileComponents();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -5,10 +5,8 @@ import {MAT_DIALOG_DATA} from '@angular/material/dialog';
|
|||||||
selector: 'app-error-dialog',
|
selector: 'app-error-dialog',
|
||||||
templateUrl: './error-dialog.component.html',
|
templateUrl: './error-dialog.component.html',
|
||||||
styleUrls: ['./error-dialog.component.scss'],
|
styleUrls: ['./error-dialog.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class ErrorDialogComponent {
|
export class ErrorDialogComponent {
|
||||||
|
|
||||||
constructor(@Inject(MAT_DIALOG_DATA) public data: any) {}
|
constructor(@Inject(MAT_DIALOG_DATA) public data: any) {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,8 @@ describe('FooterComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ FooterComponent ]
|
declarations: [FooterComponent],
|
||||||
})
|
}).compileComponents();
|
||||||
.compileComponents();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -4,13 +4,10 @@ import {ChangeDetectionStrategy, Component, OnInit} from '@angular/core';
|
|||||||
selector: 'app-footer',
|
selector: 'app-footer',
|
||||||
templateUrl: './footer.component.html',
|
templateUrl: './footer.component.html',
|
||||||
styleUrls: ['./footer.component.scss'],
|
styleUrls: ['./footer.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class FooterComponent implements OnInit {
|
export class FooterComponent implements OnInit {
|
||||||
|
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,8 @@ describe('NetworkStatusComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ NetworkStatusComponent ]
|
declarations: [NetworkStatusComponent],
|
||||||
})
|
}).compileComponents();
|
||||||
.compileComponents();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -4,19 +4,16 @@ import {Component, OnInit, ChangeDetectionStrategy, ChangeDetectorRef} from '@an
|
|||||||
selector: 'app-network-status',
|
selector: 'app-network-status',
|
||||||
templateUrl: './network-status.component.html',
|
templateUrl: './network-status.component.html',
|
||||||
styleUrls: ['./network-status.component.scss'],
|
styleUrls: ['./network-status.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class NetworkStatusComponent implements OnInit {
|
export class NetworkStatusComponent implements OnInit {
|
||||||
noInternetConnection: boolean = !navigator.onLine;
|
noInternetConnection: boolean = !navigator.onLine;
|
||||||
|
|
||||||
constructor(
|
constructor(private cdr: ChangeDetectorRef) {
|
||||||
private cdr: ChangeDetectorRef,
|
|
||||||
) {
|
|
||||||
this.handleNetworkChange();
|
this.handleNetworkChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {}
|
||||||
}
|
|
||||||
|
|
||||||
handleNetworkChange(): void {
|
handleNetworkChange(): void {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -13,8 +13,6 @@ import {MatDialogModule} from '@angular/material/dialog';
|
|||||||
import { SafePipe } from '@app/shared/_pipes/safe.pipe';
|
import { SafePipe } from '@app/shared/_pipes/safe.pipe';
|
||||||
import { NetworkStatusComponent } from './network-status/network-status.component';
|
import { NetworkStatusComponent } from './network-status/network-status.component';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
TopbarComponent,
|
TopbarComponent,
|
||||||
@ -25,7 +23,7 @@ import { NetworkStatusComponent } from './network-status/network-status.componen
|
|||||||
TokenRatioPipe,
|
TokenRatioPipe,
|
||||||
ErrorDialogComponent,
|
ErrorDialogComponent,
|
||||||
SafePipe,
|
SafePipe,
|
||||||
NetworkStatusComponent
|
NetworkStatusComponent,
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
TopbarComponent,
|
TopbarComponent,
|
||||||
@ -34,13 +32,8 @@ import { NetworkStatusComponent } from './network-status/network-status.componen
|
|||||||
MenuSelectionDirective,
|
MenuSelectionDirective,
|
||||||
TokenRatioPipe,
|
TokenRatioPipe,
|
||||||
SafePipe,
|
SafePipe,
|
||||||
NetworkStatusComponent
|
NetworkStatusComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [CommonModule, RouterModule, MatIconModule, MatDialogModule],
|
||||||
CommonModule,
|
|
||||||
RouterModule,
|
|
||||||
MatIconModule,
|
|
||||||
MatDialogModule,
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
export class SharedModule {}
|
export class SharedModule {}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user