Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8a72927755 | |||
| 26bc9541a3 | |||
| 3e8017050d | |||
| 76ca83116b | |||
| 205a65cf45 | |||
| 23e687de27 | |||
| c0612696c9 | |||
| 3eff2af69d | |||
| d69ed8082e | |||
| 7eb77671a2 | |||
| 410d3aa622 | |||
| f5b7429130 | |||
| 1e9b5817ab | |||
| d9935d2dd1 | |||
| 110118e01d | |||
| 2cf55e6709 | |||
| 46ce0ddbff | |||
| 11af9c5d0d | |||
| 886ab08b1f |
214
package-lock.json
generated
214
package-lock.json
generated
@@ -5,25 +5,25 @@
|
|||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular-devkit/architect": {
|
"@angular-devkit/architect": {
|
||||||
"version": "0.1000.2",
|
"version": "0.1000.3",
|
||||||
"resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1000.2.tgz",
|
"resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1000.3.tgz",
|
||||||
"integrity": "sha512-n1e/ZdE70C6hDauTWLAiofKDI6m88nhb91Ddqum0eeUh3HL3Ppv/sT9O+UYsab3gIdIOFJwHBpZ96SM/2Ja5NA==",
|
"integrity": "sha512-8ZszTAkRvGGMXERFvyLT6SJPfJXjNNfHamA76uDPTBXy+EijJ1XVTUr1+SYEe73E4ovtxqxAnsApEFxS7/Ni5w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@angular-devkit/core": "10.0.2",
|
"@angular-devkit/core": "10.0.3",
|
||||||
"rxjs": "6.5.5"
|
"rxjs": "6.5.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@angular-devkit/build-angular": {
|
"@angular-devkit/build-angular": {
|
||||||
"version": "0.1000.2",
|
"version": "0.1000.3",
|
||||||
"resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.1000.2.tgz",
|
"resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.1000.3.tgz",
|
||||||
"integrity": "sha512-Cl7JaXkE1OMpagMwPPNGq7IGy50p2F3R0iZFi38imq661YqH/FFv0SdbMqmpAHaIvvr6E1HJt5ltoLNERQWFjg==",
|
"integrity": "sha512-r3KJj39AwkYYzbixSM095l4fOGvhyByr0XvmAEu0l5dGGdL4tNXywvgXkNhEVRDo0jZYpTMegiTqzOik/9YCDw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@angular-devkit/architect": "0.1000.2",
|
"@angular-devkit/architect": "0.1000.3",
|
||||||
"@angular-devkit/build-optimizer": "0.1000.2",
|
"@angular-devkit/build-optimizer": "0.1000.3",
|
||||||
"@angular-devkit/build-webpack": "0.1000.2",
|
"@angular-devkit/build-webpack": "0.1000.3",
|
||||||
"@angular-devkit/core": "10.0.2",
|
"@angular-devkit/core": "10.0.3",
|
||||||
"@babel/core": "7.9.6",
|
"@babel/core": "7.9.6",
|
||||||
"@babel/generator": "7.9.6",
|
"@babel/generator": "7.9.6",
|
||||||
"@babel/plugin-transform-runtime": "7.9.6",
|
"@babel/plugin-transform-runtime": "7.9.6",
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
"@babel/runtime": "7.9.6",
|
"@babel/runtime": "7.9.6",
|
||||||
"@babel/template": "7.8.6",
|
"@babel/template": "7.8.6",
|
||||||
"@jsdevtools/coverage-istanbul-loader": "3.0.3",
|
"@jsdevtools/coverage-istanbul-loader": "3.0.3",
|
||||||
"@ngtools/webpack": "10.0.2",
|
"@ngtools/webpack": "10.0.3",
|
||||||
"ajv": "6.12.2",
|
"ajv": "6.12.2",
|
||||||
"autoprefixer": "9.8.0",
|
"autoprefixer": "9.8.0",
|
||||||
"babel-loader": "8.1.0",
|
"babel-loader": "8.1.0",
|
||||||
@@ -88,9 +88,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@angular-devkit/build-optimizer": {
|
"@angular-devkit/build-optimizer": {
|
||||||
"version": "0.1000.2",
|
"version": "0.1000.3",
|
||||||
"resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.1000.2.tgz",
|
"resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.1000.3.tgz",
|
||||||
"integrity": "sha512-wbrgJQw92+A7kFaG7U0F9MMzhVI32tcIdr26+SFXWGAeBaWIkBfMs/jfGLlEYESLqQQF5oMn7LJBwXu+nkPHvw==",
|
"integrity": "sha512-6mFoubg08UCWC0fE2mGoawEt2R1VlGStvUNAP2PRCjoj1ZySa1NnVYoKk65cyAAA3K2o7vSoDZesNq1uABjZbg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"loader-utils": "2.0.0",
|
"loader-utils": "2.0.0",
|
||||||
@@ -100,20 +100,20 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@angular-devkit/build-webpack": {
|
"@angular-devkit/build-webpack": {
|
||||||
"version": "0.1000.2",
|
"version": "0.1000.3",
|
||||||
"resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1000.2.tgz",
|
"resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1000.3.tgz",
|
||||||
"integrity": "sha512-x1fHnZFTwvAE3lB6XnlJmf0KNiiAsZKGdUuTXqzgsgh34A/aFOWtu0EB6cw6lvifMj1ioDT8Zjp8N89Lh5AtEA==",
|
"integrity": "sha512-+vmn9d9THFubSWS28K1+nElUfOrhT576ptVZMd0a5S24momV8loW3J8iBOBfnGal/P86ZCAyP46kSirlAzH9Jg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@angular-devkit/architect": "0.1000.2",
|
"@angular-devkit/architect": "0.1000.3",
|
||||||
"@angular-devkit/core": "10.0.2",
|
"@angular-devkit/core": "10.0.3",
|
||||||
"rxjs": "6.5.5"
|
"rxjs": "6.5.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@angular-devkit/core": {
|
"@angular-devkit/core": {
|
||||||
"version": "10.0.2",
|
"version": "10.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-10.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-10.0.3.tgz",
|
||||||
"integrity": "sha512-gD8iUP28GscsHqGKKu+NtX97bt7aXDZmIYqWTv4SThrcsPYY2A4tBw+NBbNAwjHkNfn4jflpqTmcN9gBAoLoSg==",
|
"integrity": "sha512-m27ogjq44j80x64RnEswSvy8UewUqeCVJBbEuY6fzrWoaiCf12sgPlrSCwjwfhtQrLgl1e/i9zYA7U6ulGRXyg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"ajv": "6.12.2",
|
"ajv": "6.12.2",
|
||||||
@@ -124,28 +124,28 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@angular-devkit/schematics": {
|
"@angular-devkit/schematics": {
|
||||||
"version": "10.0.2",
|
"version": "10.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-10.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-10.0.3.tgz",
|
||||||
"integrity": "sha512-BUUWAreHoxk4Z91Xhr+wtFUhK6+7AOczsIxlZmJnQwSUhN2ZdiDjOXeO3NFkDdL8CtNOz5khGu2iNBqn08FpUw==",
|
"integrity": "sha512-TjA2ZSPCgUK9l4FiRTIQY7DceXMAvNzOMWffy9o3kv2HPtxG9kuBrQXk++Z99zpylK0cAsugV7t/5ANpUkrIiA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@angular-devkit/core": "10.0.2",
|
"@angular-devkit/core": "10.0.3",
|
||||||
"ora": "4.0.4",
|
"ora": "4.0.4",
|
||||||
"rxjs": "6.5.5"
|
"rxjs": "6.5.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@angular/animations": {
|
"@angular/animations": {
|
||||||
"version": "10.0.3",
|
"version": "10.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@angular/animations/-/animations-10.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@angular/animations/-/animations-10.0.4.tgz",
|
||||||
"integrity": "sha512-s7hob0TmSRqsgEWdB0EYsKY8eF8iD6Sj44XntecAhEc/IxVQGIIZiNwGvW43Lb8iEdbvdF+GJfgxu5I8ZWMX3Q==",
|
"integrity": "sha512-UzQiWhDHY6wixS1Nh+Jwpzq1weiLGXJPt3Pa4pETpt3Hg7MIUu62dik6OFWuGYQPbn9DJYH+CH+sRxN1GCVjww==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@angular/cdk": {
|
"@angular/cdk": {
|
||||||
"version": "10.0.2",
|
"version": "10.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-10.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-10.1.0.tgz",
|
||||||
"integrity": "sha512-ZvZkeh7qXllAGSOFvWSYurCslflTmB0JD3gonmUKOBl/O/AcOTPntP+iOrUaC3+eR3ohsfL5SswxChW0NF+oHQ==",
|
"integrity": "sha512-zSZcpsfhRWdNAzNXnKZIlaX1uAWY+8W2zV7ktQNJoNypo9X02rY0YtmPBzlPjT0ITjM4EqohZ07nfd+5bLUw4A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"parse5": "^5.0.0",
|
"parse5": "^5.0.0",
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
@@ -160,16 +160,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@angular/cli": {
|
"@angular/cli": {
|
||||||
"version": "10.0.2",
|
"version": "10.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-10.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-10.0.3.tgz",
|
||||||
"integrity": "sha512-L/uLUrZNIwbYzIeU9R3SC2hblDgtxP57msmRjoOQBpSzwlOME+z0wlCXPv+h9NOzNPvVVbEtLtjBgZxUw0IHzg==",
|
"integrity": "sha512-ONK8YG20KuakQetY0lPKDAOA3uBoLurdpSfFspFkcECyDimwJYSEydi3FUnCxEexeoKvrQWcol+q+u9YPoHCyg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@angular-devkit/architect": "0.1000.2",
|
"@angular-devkit/architect": "0.1000.3",
|
||||||
"@angular-devkit/core": "10.0.2",
|
"@angular-devkit/core": "10.0.3",
|
||||||
"@angular-devkit/schematics": "10.0.2",
|
"@angular-devkit/schematics": "10.0.3",
|
||||||
"@schematics/angular": "10.0.2",
|
"@schematics/angular": "10.0.3",
|
||||||
"@schematics/update": "0.1000.2",
|
"@schematics/update": "0.1000.3",
|
||||||
"@yarnpkg/lockfile": "1.1.0",
|
"@yarnpkg/lockfile": "1.1.0",
|
||||||
"ansi-colors": "4.1.1",
|
"ansi-colors": "4.1.1",
|
||||||
"debug": "4.1.1",
|
"debug": "4.1.1",
|
||||||
@@ -202,25 +202,25 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@angular/common": {
|
"@angular/common": {
|
||||||
"version": "10.0.3",
|
"version": "10.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@angular/common/-/common-10.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@angular/common/-/common-10.0.4.tgz",
|
||||||
"integrity": "sha512-R2q/Vt07PHgcmvZBVGcYjf6K2xERCHWUYQYN1HsgjVQUu5ypvE7Kqs+6s0BfIoBKc+ejKmjMHHumnm+89O+gXg==",
|
"integrity": "sha512-9DJMD8GgHz7i2fMz0f1IHZlDSIz83uE6fcH8SIq1iCSWT2dubRRpCX000VpIyhAgfkCgdNCYXQ7VGNsZceoagQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@angular/compiler": {
|
"@angular/compiler": {
|
||||||
"version": "10.0.3",
|
"version": "10.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-10.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-10.0.4.tgz",
|
||||||
"integrity": "sha512-SmzMYxBprs8bVS9WctiCDj6KVp3jZFEaxGTbC/FwtdvesMIdOktpHggUeJW+OzUTwTnYVmKrm6d8rdg3QSaXFQ==",
|
"integrity": "sha512-1rnEmSHJtrKC1QD+PyF36xwMnSqG4Slgi5+PYk3BxIa5vbWBibrYijtd/uCNhscfPSpfb06MVM2mRsrc+BmbQg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@angular/compiler-cli": {
|
"@angular/compiler-cli": {
|
||||||
"version": "10.0.3",
|
"version": "10.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-10.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-10.0.4.tgz",
|
||||||
"integrity": "sha512-XK2xQX0RLr7QMkEseDhcdqZ2hMM5n1Q6LFvOJfxQXXBpa7DBC9mB6HLsn0vrLgwaAfz+SEQ7pLDgXQSy2tmJUg==",
|
"integrity": "sha512-uZKk6Ab4Pw8qcaXhpORuEoCbPSHWx3TWcs9OXIKIhzOOoMMe9OSt2SzOkHCrySSaik1IhQODnHww7sGRw5mxwQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"canonical-path": "1.0.0",
|
"canonical-path": "1.0.0",
|
||||||
@@ -401,49 +401,57 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@angular/core": {
|
"@angular/core": {
|
||||||
"version": "10.0.3",
|
"version": "10.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@angular/core/-/core-10.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@angular/core/-/core-10.0.4.tgz",
|
||||||
"integrity": "sha512-EfWAz5StlPYo2ZtvVzeoNlGrFAXRncwGd/CExbLFOZx4HcDXVkATw5d4vnKHmmKacDqnbuvMD2M0Tl0EJi5q4g==",
|
"integrity": "sha512-lA8RDagJ/O0gUX95h00+nnUZs/1QmmhAVWVtHcuI12ueC836tJhLtPGnEx9ib9NXrgRyNwb8lO1xJPmmuQgdQQ==",
|
||||||
|
"requires": {
|
||||||
|
"tslib": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@angular/flex-layout": {
|
||||||
|
"version": "10.0.0-beta.32",
|
||||||
|
"resolved": "https://registry.npmjs.org/@angular/flex-layout/-/flex-layout-10.0.0-beta.32.tgz",
|
||||||
|
"integrity": "sha512-JvuY4dUoy5jyCTIrFiq7n30Znakh1pD3nbg0h0hs2r3t1OiDQb0ZSI1wcumosG/vYHsuJQTuNhbfaIZzA1x8nA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@angular/forms": {
|
"@angular/forms": {
|
||||||
"version": "10.0.3",
|
"version": "10.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@angular/forms/-/forms-10.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@angular/forms/-/forms-10.0.4.tgz",
|
||||||
"integrity": "sha512-08XlERBGVnzea4sVY7J1JsU6zX/ENGZGB9V4K1jpX6gNjlAk2AbskC76+ngdsgdzv0neNEqPoLdMAZerNECnUg==",
|
"integrity": "sha512-SJSYZCfHua9fi/dks1q+ad9OGBblRUn3Q1V4B7r99fJYr39qRiIHcegikhY4h8H3Wk1bJRGJG7iXmxJhjWXK3Q==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@angular/material": {
|
"@angular/material": {
|
||||||
"version": "10.0.2",
|
"version": "10.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@angular/material/-/material-10.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@angular/material/-/material-10.1.0.tgz",
|
||||||
"integrity": "sha512-xG8lCG+QS+r61aDoBauH6RyNuOHai4yxhn3e8cb2ua86liarJmF9jqlW0tB49tE1ZLz9U/+ybJKkos2kX1eF1Q==",
|
"integrity": "sha512-zHJxMHYAyfJbhXGhsWUFTABBBQVzWNexuJGWh19MQx0jQn7aLek5nYQ0oLG00+ArISVAg/XMOtnbdRaemFWVzw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@angular/platform-browser": {
|
"@angular/platform-browser": {
|
||||||
"version": "10.0.3",
|
"version": "10.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-10.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-10.0.4.tgz",
|
||||||
"integrity": "sha512-f6JsFMunJNn7fPtwwWbZsXZ/JFA5RlwbyHKKkLAPMLLJwabOcSh/bUpPWKoRMHpUxr53PGEX4XY6QNPJXrUaag==",
|
"integrity": "sha512-iaZ8pFS5XUgPCO6/C47TzSFPzlzgleayq099cVOOx9z0t/SwUCSKt4AdAVhyQ8RTnx6l1JmmwBgRaXpScZlqzg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@angular/platform-browser-dynamic": {
|
"@angular/platform-browser-dynamic": {
|
||||||
"version": "10.0.3",
|
"version": "10.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-10.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-10.0.4.tgz",
|
||||||
"integrity": "sha512-ASZWymDVCgmDe0XE1djGKrfJnUR65PdfoZ51CQ7xSVJTnXp6kCAXzFeG2IyqU+O7IXvQRgvb4GOA4Y6GScNVKw==",
|
"integrity": "sha512-RoUMqYhUwF6+Mvk/aH0IZQ1D0SDEi9k5EZlx9CJ3RvNuKygk7to+S4vMWVpGxFQlwdS3bytRLKi+Kki6f4nLkg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@angular/router": {
|
"@angular/router": {
|
||||||
"version": "10.0.3",
|
"version": "10.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@angular/router/-/router-10.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@angular/router/-/router-10.0.4.tgz",
|
||||||
"integrity": "sha512-WMNJ4yS3xvgOPa73hKQNHoTCT2l+bvompxdqZSqN7dh92QtPJBXCm+qBC2jRDj4wgP7Eq5dgymh7a/dZqseFEQ==",
|
"integrity": "sha512-iDLWdmltU5pZ6M/fBKC5Kg2o9Aqb1YJ+oHXFu186BQAl2RNeNCmMQ0VaCxjpMgD/MoSxpuRuGQ6rRrCSFCxtcQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "^2.0.0"
|
"tslib": "^2.0.0"
|
||||||
}
|
}
|
||||||
@@ -1556,12 +1564,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@ngtools/webpack": {
|
"@ngtools/webpack": {
|
||||||
"version": "10.0.2",
|
"version": "10.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-10.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-10.0.3.tgz",
|
||||||
"integrity": "sha512-Py8jkc6UIHtp5TKKAMkNiKhx0goL+d7RkQEBWIvO+9e5fBGIt0Npy3dBoJ9gRldaGIjLZWlHhGsgeaYbq5dlvA==",
|
"integrity": "sha512-0TuvYMCLtsApLtCHXeDBYGEoAQXzsRLpgFxPM5W7CGcj0ecthZO4NYrMAt+J8ky//KmbxqQSFHWmss2cbirIPA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@angular-devkit/core": "10.0.2",
|
"@angular-devkit/core": "10.0.3",
|
||||||
"enhanced-resolve": "4.1.1",
|
"enhanced-resolve": "4.1.1",
|
||||||
"rxjs": "6.5.5",
|
"rxjs": "6.5.5",
|
||||||
"webpack-sources": "1.4.3"
|
"webpack-sources": "1.4.3"
|
||||||
@@ -1611,23 +1619,23 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@schematics/angular": {
|
"@schematics/angular": {
|
||||||
"version": "10.0.2",
|
"version": "10.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-10.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-10.0.3.tgz",
|
||||||
"integrity": "sha512-viSf1HQH2vxZAonkfdAjJ/0Z8VgKptsi4UYtJDwabKRbbyp2EQ/vhEPI/ddV4QgrQqR8mkOl7nu8JqL2M0+v6A==",
|
"integrity": "sha512-Or2pCqjpPbAvmbxtfMosGwQbNbSL4xodK5Key7678ZAPGB+rcxrVkBI9yxEJ/qzF/LrmMoKqy0JCmVLK7Grpog==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@angular-devkit/core": "10.0.2",
|
"@angular-devkit/core": "10.0.3",
|
||||||
"@angular-devkit/schematics": "10.0.2"
|
"@angular-devkit/schematics": "10.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@schematics/update": {
|
"@schematics/update": {
|
||||||
"version": "0.1000.2",
|
"version": "0.1000.3",
|
||||||
"resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.1000.2.tgz",
|
"resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.1000.3.tgz",
|
||||||
"integrity": "sha512-6PSJ+WexBqY0ESo0Kp6fa9wPWAXKE9oyLNjISJ1S9QKCVowoHa8FV+7BalVOUYwUhnUzwPCF6n7PqcJiZR632g==",
|
"integrity": "sha512-Nncdklmzi1tyzkoAh7GlSslxriRhftlmfqPVmFHrrPRttYACtT/QH5qcWsrPgTPpHGINYEHrPjpeljsMoMchBQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@angular-devkit/core": "10.0.2",
|
"@angular-devkit/core": "10.0.3",
|
||||||
"@angular-devkit/schematics": "10.0.2",
|
"@angular-devkit/schematics": "10.0.3",
|
||||||
"@yarnpkg/lockfile": "1.1.0",
|
"@yarnpkg/lockfile": "1.1.0",
|
||||||
"ini": "1.3.5",
|
"ini": "1.3.5",
|
||||||
"npm-package-arg": "^8.0.0",
|
"npm-package-arg": "^8.0.0",
|
||||||
@@ -2899,9 +2907,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"caniuse-lite": {
|
"caniuse-lite": {
|
||||||
"version": "1.0.30001100",
|
"version": "1.0.30001104",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001100.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001104.tgz",
|
||||||
"integrity": "sha512-0eYdp1+wFCnMlCj2oudciuQn2B9xAFq3WpgpcBIZTxk/1HNA/O2YA7rpeYhnOqsqAJq1AHUgx6i1jtafg7m2zA==",
|
"integrity": "sha512-pkpCg7dmI/a7WcqM2yfdOiT4Xx5tzyoHAXWsX5/HxZ3TemwDZs0QXdqbE0UPLPVy/7BeK7693YfzfRYfu1YVpg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"canonical-path": {
|
"canonical-path": {
|
||||||
@@ -3027,9 +3035,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"cli-spinners": {
|
"cli-spinners": {
|
||||||
"version": "2.3.0",
|
"version": "2.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.4.0.tgz",
|
||||||
"integrity": "sha512-Xs2Hf2nzrvJMFKimOR7YR0QwZ8fc0u98kdtwN1eNAZzNQgH3vK2pXzff6GJtKh7S5hoJ87ECiAiZFS2fb5Ii2w==",
|
"integrity": "sha512-sJAofoarcm76ZGpuooaO0eDy8saEy+YoZBLjC4h8srt4jeBnkYeOgqxgsJQTpyt2LjI5PTfLJHSL+41Yu4fEJA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"cli-width": {
|
"cli-width": {
|
||||||
@@ -4324,9 +4332,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"electron-to-chromium": {
|
"electron-to-chromium": {
|
||||||
"version": "1.3.498",
|
"version": "1.3.501",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.498.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.501.tgz",
|
||||||
"integrity": "sha512-W1hGwaQEU8j9su2jeAr3aabkPuuXw+j8t73eajGAkEJWbfWiwbxBwQN/8Qmv2qCy3uCDm2rOAaZneYQM8VGC4w==",
|
"integrity": "sha512-tyzuKaV2POw2mtqBBzQGNBojMZzH0MRu8bT8T/50x+hWeucyG/9pkgAATy+PcM2ySNM9+8eG2VllY9c6j4i+bg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"elliptic": {
|
"elliptic": {
|
||||||
@@ -6990,9 +6998,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"less": {
|
"less": {
|
||||||
"version": "3.12.0",
|
"version": "3.12.2",
|
||||||
"resolved": "https://registry.npmjs.org/less/-/less-3.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/less/-/less-3.12.2.tgz",
|
||||||
"integrity": "sha512-3mmSHFRP9hGxxQgAKgChfau1LO3ksV/zyZf1qd2ENyBV778NA9Ids99wFRA20jE+5prT7oScKod8PoGlxSe1gg==",
|
"integrity": "sha512-+1V2PCMFkL+OIj2/HrtrvZw0BC0sYLMICJfbQjuj/K8CEnlrFX6R5cKKgzzttsZDHyxQNL1jqMREjKN3ja/E3Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"errno": "^0.1.1",
|
"errno": "^0.1.1",
|
||||||
@@ -7687,9 +7695,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"native-request": {
|
"native-request": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/native-request/-/native-request-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/native-request/-/native-request-1.0.7.tgz",
|
||||||
"integrity": "sha512-7wU3DvBGAJQxWuMR3F62zrhB7hxNj2DdlC/eBVrCgavc6+ZpFZOqS/PsR7QyUPLMkFk0GvvzoeeOAZGLLnObnA==",
|
"integrity": "sha512-9nRjinI9bmz+S7dgNtf4A70+/vPhnd+2krGpy4SUlADuOuSa24IDkNaZ+R/QT1wQ6S8jBdi6wE7fLekFZNfUpQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
@@ -8692,9 +8700,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"portfinder": {
|
"portfinder": {
|
||||||
"version": "1.0.26",
|
"version": "1.0.27",
|
||||||
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.26.tgz",
|
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.27.tgz",
|
||||||
"integrity": "sha512-Xi7mKxJHHMI3rIUrnm/jjUgwhbYMkp/XKEcZX3aG4BrumLpq3nmoQMX+ClYnDZnZ/New7IatC1no5RX0zo1vXQ==",
|
"integrity": "sha512-bJ3U3MThKnyJ9Dx1Idtm5pQmxXqw08+XOHhi/Lie8OF1OlhVaBFhsntAIhkZYjfDcCzszSr0w1yCbccThhzgxQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"async": "^2.6.2",
|
"async": "^2.6.2",
|
||||||
@@ -12018,9 +12026,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "3.9.6",
|
"version": "3.9.7",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.6.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz",
|
||||||
"integrity": "sha512-Pspx3oKAPJtjNwE92YS05HQoY7z2SFyOpHo9MqJor3BXAGNaPUs83CuVp9VISFkSjyRfiTpmKuAYGJB7S7hOxw==",
|
"integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"ua-parser-js": {
|
"ua-parser-js": {
|
||||||
|
|||||||
31
package.json
31
package.json
@@ -11,28 +11,29 @@
|
|||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "~10.0.3",
|
"@angular/animations": "^10.0.4",
|
||||||
"@angular/cdk": "^10.0.2",
|
"@angular/cdk": "^10.1.0",
|
||||||
"@angular/common": "~10.0.3",
|
"@angular/common": "^10.0.4",
|
||||||
"@angular/compiler": "~10.0.3",
|
"@angular/compiler": "^10.0.4",
|
||||||
"@angular/core": "~10.0.3",
|
"@angular/core": "^10.0.4",
|
||||||
"@angular/forms": "~10.0.3",
|
"@angular/flex-layout": "^10.0.0-beta.32",
|
||||||
"@angular/material": "^10.0.2",
|
"@angular/forms": "^10.0.4",
|
||||||
"@angular/platform-browser": "~10.0.3",
|
"@angular/material": "^10.1.0",
|
||||||
"@angular/platform-browser-dynamic": "~10.0.3",
|
"@angular/platform-browser": "^10.0.4",
|
||||||
"@angular/router": "~10.0.3",
|
"@angular/platform-browser-dynamic": "^10.0.4",
|
||||||
|
"@angular/router": "^10.0.4",
|
||||||
"rxjs": "~6.5.5",
|
"rxjs": "~6.5.5",
|
||||||
"socket.io": "^2.3.0",
|
"socket.io": "^2.3.0",
|
||||||
"tslib": "^2.0.0",
|
"tslib": "^2.0.0",
|
||||||
"zone.js": "~0.10.3"
|
"zone.js": "~0.10.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-devkit/build-angular": "~0.1000.2",
|
"@angular-devkit/build-angular": "^0.1000.3",
|
||||||
"@angular/cli": "~10.0.2",
|
"@angular/cli": "^10.0.3",
|
||||||
"@angular/compiler-cli": "~10.0.3",
|
"@angular/compiler-cli": "^10.0.4",
|
||||||
"@types/node": "^12.11.1",
|
|
||||||
"@types/jasmine": "~3.5.0",
|
"@types/jasmine": "~3.5.0",
|
||||||
"@types/jasminewd2": "~2.0.3",
|
"@types/jasminewd2": "~2.0.3",
|
||||||
|
"@types/node": "^12.11.1",
|
||||||
"codelyzer": "^6.0.0",
|
"codelyzer": "^6.0.0",
|
||||||
"jasmine-core": "~3.5.0",
|
"jasmine-core": "~3.5.0",
|
||||||
"jasmine-spec-reporter": "~5.0.0",
|
"jasmine-spec-reporter": "~5.0.0",
|
||||||
@@ -44,6 +45,6 @@
|
|||||||
"protractor": "~7.0.0",
|
"protractor": "~7.0.0",
|
||||||
"ts-node": "~8.3.0",
|
"ts-node": "~8.3.0",
|
||||||
"tslint": "~6.1.0",
|
"tslint": "~6.1.0",
|
||||||
"typescript": "~3.9.5"
|
"typescript": "^3.9.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
src/app/account/account.service.spec.ts
Normal file
16
src/app/account/account.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AccountService } from './account.service';
|
||||||
|
|
||||||
|
describe('AccountService', () => {
|
||||||
|
let service: AccountService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(AccountService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
38
src/app/account/account.service.ts
Normal file
38
src/app/account/account.service.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { BehaviorSubject, Observable } from 'rxjs';
|
||||||
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { environment } from '../../environments/environment';
|
||||||
|
import { User } from './user';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class AccountService {
|
||||||
|
private userSubject: BehaviorSubject<User>;
|
||||||
|
public user: Observable<User>;
|
||||||
|
|
||||||
|
constructor(private httpClient: HttpClient) {
|
||||||
|
this.userSubject = new BehaviorSubject<User>(JSON.parse(localStorage.getItem('user')));
|
||||||
|
this.user = this.userSubject.asObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public get userValue() {
|
||||||
|
return this.userSubject.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
login(username, password) {
|
||||||
|
return this.httpClient.post<User>(environment.apiUrl + '/fake_login', { username, password })
|
||||||
|
.pipe((map(user => {
|
||||||
|
localStorage.setItem('user', JSON.stringify(user));
|
||||||
|
this.userSubject.next(user);
|
||||||
|
return user;
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
|
register(user) {
|
||||||
|
return this.httpClient.post<User>(environment.apiUrl + '/fake_registration', user);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
7
src/app/account/auth.guard.spec.ts
Normal file
7
src/app/account/auth.guard.spec.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { AuthGuard } from './auth.guard';
|
||||||
|
|
||||||
|
describe('Auth.Guard', () => {
|
||||||
|
it('should create an instance', () => {
|
||||||
|
expect(new AuthGuard()).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
21
src/app/account/auth.guard.ts
Normal file
21
src/app/account/auth.guard.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
||||||
|
import { AccountService } from './account.service';
|
||||||
|
|
||||||
|
@Injectable({providedIn: 'root'})
|
||||||
|
export class AuthGuard implements CanActivate {
|
||||||
|
constructor(private router: Router,
|
||||||
|
private accountService: AccountService) { }
|
||||||
|
|
||||||
|
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
|
||||||
|
const user = this.accountService.userValue;
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.router.navigate(['/login'], {queryParams: {returnURL: state.url}});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
22
src/app/account/login/login.component.css
Normal file
22
src/app/account/login/login.component.css
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
.login-card {
|
||||||
|
width: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form {
|
||||||
|
padding: 10px 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-button {
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-form-field {
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 15px;
|
||||||
|
}
|
||||||
30
src/app/account/login/login.component.html
Normal file
30
src/app/account/login/login.component.html
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<div class="login-container" fxLayout="row" fxLayoutAlign="center center">
|
||||||
|
<mat-card class="login-card" fxLayout="column" fxLayoutAlign="center center">
|
||||||
|
<mat-card-title>Login</mat-card-title>
|
||||||
|
<mat-card-content>
|
||||||
|
<form class="login-form" [formGroup]="form" (ngSubmit)="onLogin()">
|
||||||
|
<mat-form-field appearance="fill">
|
||||||
|
<mat-label>User name</mat-label>
|
||||||
|
<label>
|
||||||
|
<input matInput formControlName="username" required>
|
||||||
|
</label>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field appearance="fill">
|
||||||
|
<mat-label>Password</mat-label>
|
||||||
|
<label>
|
||||||
|
<input matInput formControlName="password" type="password" required minlength="15">
|
||||||
|
</label>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<div fxLayout="row" fxLayoutAlign="space-evenly center">
|
||||||
|
<button mat-flat-button color="primary" [disabled]="loading">
|
||||||
|
<span *ngIf="loading" class="spinner-border spinner-border-sm mr-1"></span>
|
||||||
|
Login
|
||||||
|
</button>
|
||||||
|
<a mat-button routerLink="/register">Sign up</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
25
src/app/account/login/login.component.spec.ts
Normal file
25
src/app/account/login/login.component.spec.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { LoginComponent } from './login.component';
|
||||||
|
|
||||||
|
describe('LoginComponent', () => {
|
||||||
|
let component: LoginComponent;
|
||||||
|
let fixture: ComponentFixture<LoginComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ LoginComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(LoginComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
42
src/app/account/login/login.component.ts
Normal file
42
src/app/account/login/login.component.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { FormControl, FormGroup } from '@angular/forms';
|
||||||
|
import { AccountService } from '../account.service';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { first } from 'rxjs/operators';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-login',
|
||||||
|
templateUrl: './login.component.html',
|
||||||
|
styleUrls: ['./login.component.css']
|
||||||
|
})
|
||||||
|
export class LoginComponent implements OnInit {
|
||||||
|
form: FormGroup = new FormGroup({
|
||||||
|
username: new FormControl(''),
|
||||||
|
password: new FormControl(''),
|
||||||
|
});
|
||||||
|
loading = false;
|
||||||
|
returnUrl = this.activatedRoute.snapshot.queryParams['returnUrl'] || '/';
|
||||||
|
|
||||||
|
onLogin() {
|
||||||
|
this.loading = true;
|
||||||
|
this.accountService.login(this.form.controls['username'], this.form.controls['password'])
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe(data => {
|
||||||
|
this.router.navigate([this.returnUrl]);
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
// TODO error handling
|
||||||
|
console.log(error);
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(private accountService: AccountService,
|
||||||
|
private activatedRoute: ActivatedRoute,
|
||||||
|
private router: Router,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { PasswordErrorStateMatcher } from './password-error-state-matcher';
|
||||||
|
|
||||||
|
describe('PasswordErrorStateMatcher', () => {
|
||||||
|
it('should create an instance', () => {
|
||||||
|
expect(new PasswordErrorStateMatcher()).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
11
src/app/account/register/password-error-state-matcher.ts
Normal file
11
src/app/account/register/password-error-state-matcher.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { ErrorStateMatcher } from '@angular/material/core';
|
||||||
|
import { FormControl, FormGroupDirective, NgForm } from '@angular/forms';
|
||||||
|
|
||||||
|
export class PasswordErrorStateMatcher implements ErrorStateMatcher {
|
||||||
|
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
|
||||||
|
const invalidControl = !!(control && control.invalid && control.parent.touched);
|
||||||
|
const invalidParent = !!(control && control.parent && control.parent.invalid && control.parent.touched);
|
||||||
|
|
||||||
|
return invalidControl || invalidParent;
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/app/account/register/register.component.css
Normal file
22
src/app/account/register/register.component.css
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
.register-card {
|
||||||
|
width: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-form {
|
||||||
|
padding: 10px 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-button {
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-form-field {
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 15px;
|
||||||
|
}
|
||||||
48
src/app/account/register/register.component.html
Normal file
48
src/app/account/register/register.component.html
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<div class="register-container" fxLayout="row" fxLayoutAlign="center center">
|
||||||
|
<mat-card class="register-card" fxLayout="column" fxLayoutAlign="center center">
|
||||||
|
<mat-card-title>Sign up</mat-card-title>
|
||||||
|
<mat-card-content>
|
||||||
|
<form class="register-form" [formGroup]="form" (ngSubmit)="onRegister()">
|
||||||
|
<mat-form-field appearance="fill">
|
||||||
|
<mat-label>User name</mat-label>
|
||||||
|
<label>
|
||||||
|
<input matInput formControlName="username" required>
|
||||||
|
</label>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field appearance="fill">
|
||||||
|
<mat-label>Email</mat-label>
|
||||||
|
<label>
|
||||||
|
<input matInput formControlName="email" required email>
|
||||||
|
</label>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<div formGroupName="password">
|
||||||
|
<mat-form-field appearance="fill" hintLabel="At least 15 characters.">
|
||||||
|
<mat-label>Password</mat-label>
|
||||||
|
<label>
|
||||||
|
<input matInput formControlName="first" type="password" required minlength="15">
|
||||||
|
</label>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field appearance="fill">
|
||||||
|
<mat-label>Confirm password</mat-label>
|
||||||
|
<label>
|
||||||
|
<input matInput formControlName="second" type="password" required minlength="15"
|
||||||
|
[errorStateMatcher]="passwordErrorStateMatcher">
|
||||||
|
</label>
|
||||||
|
<mat-error *ngIf="form.get('password').hasError('mismatch')">Passwords don't match.</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div fxLayout="row" fxLayoutAlign="space-evenly center">
|
||||||
|
<button mat-flat-button color="primary" [disabled]="loading">
|
||||||
|
<span *ngIf="loading" class="spinner-border spinner-border-sm mr-1"></span>
|
||||||
|
Sign up
|
||||||
|
</button>
|
||||||
|
<a mat-button routerLink="/login">Login</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
25
src/app/account/register/register.component.spec.ts
Normal file
25
src/app/account/register/register.component.spec.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { RegisterComponent } from './register.component';
|
||||||
|
|
||||||
|
describe('RegisterComponent', () => {
|
||||||
|
let component: RegisterComponent;
|
||||||
|
let fixture: ComponentFixture<RegisterComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ RegisterComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(RegisterComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
65
src/app/account/register/register.component.ts
Normal file
65
src/app/account/register/register.component.ts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { FormBuilder, FormGroup, ValidationErrors, Validators } from '@angular/forms';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { first } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { AccountService } from '../account.service';
|
||||||
|
import { PasswordErrorStateMatcher } from './password-error-state-matcher';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-register',
|
||||||
|
templateUrl: './register.component.html',
|
||||||
|
styleUrls: ['./register.component.css']
|
||||||
|
})
|
||||||
|
export class RegisterComponent implements OnInit {
|
||||||
|
form = this.formBuilder.group({
|
||||||
|
username: ['', Validators.required],
|
||||||
|
email: ['', [Validators.required, Validators.email]],
|
||||||
|
password: this.formBuilder.group({
|
||||||
|
first: ['', [Validators.required, Validators.minLength(15)]],
|
||||||
|
second: ['', [Validators.required, Validators.minLength(15)]],
|
||||||
|
},
|
||||||
|
{ validators: this.passwordsEqual }),
|
||||||
|
});
|
||||||
|
loading = false;
|
||||||
|
passwordErrorStateMatcher = new PasswordErrorStateMatcher();
|
||||||
|
|
||||||
|
constructor(private accountService: AccountService,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private router: Router,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
passwordsEqual(passwords: FormGroup): ValidationErrors | null {
|
||||||
|
const password1 = passwords.get('first');
|
||||||
|
const password2 = passwords.get('second');
|
||||||
|
|
||||||
|
return password1 && password2 && password1.value === password2.value ? null : { mismatch: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
readForm() {
|
||||||
|
return {
|
||||||
|
username: this.form.get('username').value,
|
||||||
|
email: this.form.get('email').value,
|
||||||
|
password: this.form.get('password').get('first').value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onRegister() {
|
||||||
|
if (this.form.invalid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.loading = true;
|
||||||
|
this.accountService.register(this.readForm())
|
||||||
|
.pipe(first())
|
||||||
|
.subscribe(data => {
|
||||||
|
this.router.navigate(['/login']);
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
// TODO error handling
|
||||||
|
console.log(error);
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void { }
|
||||||
|
}
|
||||||
7
src/app/account/user.spec.ts
Normal file
7
src/app/account/user.spec.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { User } from './user';
|
||||||
|
|
||||||
|
describe('User', () => {
|
||||||
|
it('should create an instance', () => {
|
||||||
|
expect(new User()).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
6
src/app/account/user.ts
Normal file
6
src/app/account/user.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export class User {
|
||||||
|
id: number;
|
||||||
|
username: string;
|
||||||
|
email: string;
|
||||||
|
token: string;
|
||||||
|
}
|
||||||
@@ -1,8 +1,17 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { Routes, RouterModule } from '@angular/router';
|
import { Routes, RouterModule } from '@angular/router';
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
import { AuthGuard } from './account/auth.guard';
|
||||||
|
import { LoginComponent } from './account/login/login.component';
|
||||||
|
import { RegisterComponent } from './account/register/register.component';
|
||||||
|
|
||||||
|
|
||||||
const routes: Routes = [];
|
const routes: Routes = [
|
||||||
|
{ path: '', component: AppComponent, canActivate: [AuthGuard] },
|
||||||
|
{ path: 'login', component: LoginComponent },
|
||||||
|
{ path: 'register', component: RegisterComponent },
|
||||||
|
{ path: '**', redirectTo: '' },
|
||||||
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forRoot(routes)],
|
imports: [RouterModule.forRoot(routes)],
|
||||||
|
|||||||
@@ -16,69 +16,6 @@ svg.material-icons:not(:last-child) {
|
|||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card svg.material-icons path {
|
|
||||||
fill: #888;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-container {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: center;
|
|
||||||
/* margin-top: 16px; */
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
border-radius: 4px;
|
|
||||||
border: 1px solid #eee;
|
|
||||||
background-color: #fafafa;
|
|
||||||
height: 40px;
|
|
||||||
width: 200px;
|
|
||||||
margin: 0 8px 16px;
|
|
||||||
padding: 16px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
transition: all 0.2s ease-in-out;
|
|
||||||
line-height: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-container .card:not(:last-child) {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card.card-small {
|
|
||||||
height: 16px;
|
|
||||||
width: 168px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-container .card:not(.highlight-card) {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-container .card:not(.highlight-card):hover {
|
|
||||||
transform: translateY(-3px);
|
|
||||||
box-shadow: 0 4px 17px rgba(0, 0, 0, 0.35);
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-container .card:not(.highlight-card):hover .material-icons path {
|
|
||||||
fill: rgb(105, 103, 103);
|
|
||||||
}
|
|
||||||
|
|
||||||
.card.highlight-card {
|
|
||||||
background-color: #1976d2;
|
|
||||||
color: white;
|
|
||||||
font-weight: 600;
|
|
||||||
border: none;
|
|
||||||
width: auto;
|
|
||||||
min-width: 30%;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card.card.highlight-card span {
|
|
||||||
margin-left: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Responsive Styles */
|
/* Responsive Styles */
|
||||||
@media screen and (max-width: 767px) {
|
@media screen and (max-width: 767px) {
|
||||||
|
|
||||||
@@ -93,6 +30,10 @@ svg.material-icons:not(:last-child) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.router {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.chat {
|
.chat {
|
||||||
float: right;
|
float: right;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|||||||
@@ -1,20 +1,3 @@
|
|||||||
<div class="chat">
|
<div class="router">
|
||||||
<app-chat></app-chat>
|
<router-outlet></router-outlet>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
|
||||||
<div class="card-container">
|
|
||||||
<div class="card card-small" (click)="onClickSocket()" tabindex="0">
|
|
||||||
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
|
|
||||||
|
|
||||||
<span>Send test message</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card card-small" (click)="onClickApi()" tabindex="0">
|
|
||||||
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
|
|
||||||
|
|
||||||
<span>Call rest api</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<router-outlet></router-outlet>
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { SocketService } from './socket/socket.service';
|
import { SocketService } from './socket/socket.service';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { AccountService } from './account/account.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
@@ -10,22 +10,14 @@ import { HttpClient } from '@angular/common/http';
|
|||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
title = 'rona-frontend';
|
title = 'rona-frontend';
|
||||||
|
|
||||||
onClickSocket() {
|
|
||||||
this.socketService.send('test', {'user': 'USERNAME', 'payload': 'PAYLOAD TEST'})
|
|
||||||
}
|
|
||||||
|
|
||||||
onClickApi() {
|
|
||||||
this.httpService.get('http://localhost:5005/').subscribe(response => {
|
|
||||||
console.log('REST API call returned: ', response);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
* @param accountService
|
||||||
* @param socketService
|
* @param socketService
|
||||||
* @param httpService
|
|
||||||
*/
|
*/
|
||||||
constructor(private socketService: SocketService,
|
constructor(private accountService: AccountService,
|
||||||
private httpService: HttpClient) { }
|
private socketService: SocketService,
|
||||||
|
) { }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,50 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
|
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||||
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatCardModule } from '@angular/material/card';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { MatInputModule } from '@angular/material/input';
|
||||||
|
|
||||||
import { AppRoutingModule } from './app-routing.module';
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
|
||||||
import { ChatComponent } from './chat/chat.component';
|
import { ChatComponent } from './chat/chat.component';
|
||||||
import { EntryComponent } from './chat/entry/entry.component';
|
import { EntryComponent } from './chat/entry/entry.component';
|
||||||
import { InputComponent } from './chat/input/input.component';
|
import { InputComponent } from './chat/input/input.component';
|
||||||
import {MatCardModule} from '@angular/material/card';
|
import { LoginComponent } from './account/login/login.component';
|
||||||
import {MatInputModule} from '@angular/material/input';
|
import { TestComponent } from './test/test.component';
|
||||||
|
import { RegisterComponent } from './account/register/register.component';
|
||||||
|
import { fakeBackendProvider } from './utils/fake-backend';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
ChatComponent,
|
ChatComponent,
|
||||||
EntryComponent,
|
EntryComponent,
|
||||||
InputComponent
|
InputComponent,
|
||||||
|
LoginComponent,
|
||||||
|
TestComponent,
|
||||||
|
RegisterComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
HttpClientModule,
|
||||||
|
BrowserModule,
|
||||||
|
BrowserAnimationsModule,
|
||||||
|
FlexLayoutModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatCardModule,
|
||||||
|
MatIconModule,
|
||||||
|
MatInputModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
AppRoutingModule,
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
fakeBackendProvider,
|
||||||
],
|
],
|
||||||
imports: [
|
|
||||||
BrowserModule,
|
|
||||||
HttpClientModule,
|
|
||||||
AppRoutingModule,
|
|
||||||
BrowserAnimationsModule,
|
|
||||||
MatCardModule,
|
|
||||||
MatInputModule
|
|
||||||
],
|
|
||||||
providers: [],
|
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
export class AppModule { }
|
export class AppModule { }
|
||||||
|
|||||||
0
src/app/test/test.component.css
Normal file
0
src/app/test/test.component.css
Normal file
15
src/app/test/test.component.html
Normal file
15
src/app/test/test.component.html
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<div>
|
||||||
|
<div class="card-container">
|
||||||
|
<div class="card card-small" (click)="onClickSocket()" tabindex="0">
|
||||||
|
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
|
||||||
|
|
||||||
|
<span>Send test message</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-small" (click)="onClickApi()" tabindex="0">
|
||||||
|
<svg class="material-icons" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
|
||||||
|
|
||||||
|
<span>Call rest api</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
25
src/app/test/test.component.spec.ts
Normal file
25
src/app/test/test.component.spec.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { TestComponent } from './test.component';
|
||||||
|
|
||||||
|
describe('TestComponent', () => {
|
||||||
|
let component: TestComponent;
|
||||||
|
let fixture: ComponentFixture<TestComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ TestComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(TestComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
29
src/app/test/test.component.ts
Normal file
29
src/app/test/test.component.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import {SocketService} from '../socket/socket.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-test',
|
||||||
|
templateUrl: './test.component.html',
|
||||||
|
styleUrls: ['./test.component.css']
|
||||||
|
})
|
||||||
|
export class TestComponent implements OnInit {
|
||||||
|
|
||||||
|
onClickSocket() {
|
||||||
|
this.socketService.send('test', {'user': 'USERNAME', 'payload': 'PAYLOAD TEST'})
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickApi() {
|
||||||
|
this.httpService.get('http://localhost:5005/').subscribe(response => {
|
||||||
|
console.log('REST API call returned: ', response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(private httpService: HttpClient,
|
||||||
|
private socketService: SocketService,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
7
src/app/utils/fake-backend.spec.ts
Normal file
7
src/app/utils/fake-backend.spec.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { FakeBackend } from './fake-backend';
|
||||||
|
|
||||||
|
describe('FakeBackend', () => {
|
||||||
|
it('should create an instance', () => {
|
||||||
|
expect(new FakeBackend()).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
73
src/app/utils/fake-backend.ts
Normal file
73
src/app/utils/fake-backend.ts
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { HttpRequest, HttpResponse, HttpHandler, HttpEvent, HttpInterceptor, HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||||
|
import { Observable, of, throwError } from 'rxjs';
|
||||||
|
import { delay, mergeMap, materialize, dematerialize } from 'rxjs/operators';
|
||||||
|
|
||||||
|
|
||||||
|
let users = JSON.parse(localStorage.getItem('users')) || [];
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class FakeBackend implements HttpInterceptor {
|
||||||
|
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
|
const { url, method, headers, body } = request;
|
||||||
|
|
||||||
|
return of(null)
|
||||||
|
.pipe(mergeMap(handleRoute))
|
||||||
|
.pipe(materialize())
|
||||||
|
.pipe(delay(500))
|
||||||
|
.pipe(dematerialize());
|
||||||
|
|
||||||
|
function handleRoute() {
|
||||||
|
switch (true) {
|
||||||
|
case url.endsWith('fake_login') && method === 'POST':
|
||||||
|
return authenticate();
|
||||||
|
case url.endsWith('fake_registration') && method === 'POST':
|
||||||
|
return register();
|
||||||
|
default:
|
||||||
|
return next.handle(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function authenticate() {
|
||||||
|
const { username, password } = body;
|
||||||
|
const user = users.find(x => x.username === username.value && x.password === password.value);
|
||||||
|
if (!user) {
|
||||||
|
console.log(password);
|
||||||
|
return error('Username or password is incorrect.');
|
||||||
|
}
|
||||||
|
return ok({
|
||||||
|
id: user.id,
|
||||||
|
username: user.username,
|
||||||
|
token: 'fake-jwt-token',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function register() {
|
||||||
|
const user = body;
|
||||||
|
|
||||||
|
if (users.find(x => x.username === user.username)) {
|
||||||
|
return error('Username ' + user.username + ' is already taken.');
|
||||||
|
}
|
||||||
|
|
||||||
|
user.id = users.length ? Math.max(...users.map(x => x.id)) + 1 : 1;
|
||||||
|
users.push(user);
|
||||||
|
localStorage.setItem('users', JSON.stringify(users));
|
||||||
|
console.log('Register user: ' + user);
|
||||||
|
return ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
function ok(body?) {
|
||||||
|
return of(new HttpResponse({ status: 200, body }));
|
||||||
|
}
|
||||||
|
|
||||||
|
function error(message) {
|
||||||
|
return throwError({ error: { message } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const fakeBackendProvider = {
|
||||||
|
provide: HTTP_INTERCEPTORS,
|
||||||
|
useClass: FakeBackend,
|
||||||
|
multi: true,
|
||||||
|
}
|
||||||
@@ -3,7 +3,8 @@
|
|||||||
// The list of file replacements can be found in `angular.json`.
|
// The list of file replacements can be found in `angular.json`.
|
||||||
|
|
||||||
export const environment = {
|
export const environment = {
|
||||||
production: false
|
production: false,
|
||||||
|
apiUrl: 'http://localhost:4200',
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -10,6 +10,6 @@
|
|||||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<app-root></app-root>
|
<app-root></app-root>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user