Compare commits

19 Commits
main ... login

Author SHA1 Message Date
8a72927755 fixed indentation in index.html 2020-07-21 15:27:17 +02:00
26bc9541a3 fixed import formatting in app-routing.module.ts 2020-07-21 15:26:53 +02:00
3e8017050d added apiUrl to environment 2020-07-21 15:26:12 +02:00
76ca83116b changed button design in LoginComponent 2020-07-21 15:25:51 +02:00
205a65cf45 added login functionality to LoginComponent 2020-07-21 15:25:12 +02:00
23e687de27 added registration functionality to RegisterComponent 2020-07-21 15:24:25 +02:00
c0612696c9 updated RegisterComponent to FormBuilder and added proper input validation 2020-07-21 15:23:46 +02:00
3eff2af69d added custom ErrorStateMatcher to show feedback von Password Confirmation 2020-07-21 15:22:43 +02:00
d69ed8082e added fake-backend to AppModule 2020-07-21 15:21:45 +02:00
7eb77671a2 adjusted AuthGuard for BehaviorSubject in AccountService 2020-07-21 15:20:16 +02:00
410d3aa622 added login and register methods to AccountService 2020-07-21 15:19:49 +02:00
f5b7429130 added class to represent user 2020-07-21 15:18:53 +02:00
1e9b5817ab added fake-backend for login and registration testing 2020-07-21 15:17:51 +02:00
d9935d2dd1 added test component containing the old test setup with two buttons for websocket and rest api testing respectively 2020-07-21 08:47:59 +02:00
110118e01d changed app structure to pure router-outlet and added login and register to routing 2020-07-21 08:47:33 +02:00
2cf55e6709 added registration component 2020-07-21 08:46:11 +02:00
46ce0ddbff added login component 2020-07-21 08:45:59 +02:00
11af9c5d0d added basic AccountService 2020-07-21 08:45:40 +02:00
886ab08b1f updated packages and added @angular/flex-layout and @angular/cdk 2020-07-21 08:42:07 +02:00
31 changed files with 724 additions and 230 deletions

214
package-lock.json generated
View File

@@ -5,25 +5,25 @@
"requires": true,
"dependencies": {
"@angular-devkit/architect": {
"version": "0.1000.2",
"resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1000.2.tgz",
"integrity": "sha512-n1e/ZdE70C6hDauTWLAiofKDI6m88nhb91Ddqum0eeUh3HL3Ppv/sT9O+UYsab3gIdIOFJwHBpZ96SM/2Ja5NA==",
"version": "0.1000.3",
"resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1000.3.tgz",
"integrity": "sha512-8ZszTAkRvGGMXERFvyLT6SJPfJXjNNfHamA76uDPTBXy+EijJ1XVTUr1+SYEe73E4ovtxqxAnsApEFxS7/Ni5w==",
"dev": true,
"requires": {
"@angular-devkit/core": "10.0.2",
"@angular-devkit/core": "10.0.3",
"rxjs": "6.5.5"
}
},
"@angular-devkit/build-angular": {
"version": "0.1000.2",
"resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.1000.2.tgz",
"integrity": "sha512-Cl7JaXkE1OMpagMwPPNGq7IGy50p2F3R0iZFi38imq661YqH/FFv0SdbMqmpAHaIvvr6E1HJt5ltoLNERQWFjg==",
"version": "0.1000.3",
"resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.1000.3.tgz",
"integrity": "sha512-r3KJj39AwkYYzbixSM095l4fOGvhyByr0XvmAEu0l5dGGdL4tNXywvgXkNhEVRDo0jZYpTMegiTqzOik/9YCDw==",
"dev": true,
"requires": {
"@angular-devkit/architect": "0.1000.2",
"@angular-devkit/build-optimizer": "0.1000.2",
"@angular-devkit/build-webpack": "0.1000.2",
"@angular-devkit/core": "10.0.2",
"@angular-devkit/architect": "0.1000.3",
"@angular-devkit/build-optimizer": "0.1000.3",
"@angular-devkit/build-webpack": "0.1000.3",
"@angular-devkit/core": "10.0.3",
"@babel/core": "7.9.6",
"@babel/generator": "7.9.6",
"@babel/plugin-transform-runtime": "7.9.6",
@@ -31,7 +31,7 @@
"@babel/runtime": "7.9.6",
"@babel/template": "7.8.6",
"@jsdevtools/coverage-istanbul-loader": "3.0.3",
"@ngtools/webpack": "10.0.2",
"@ngtools/webpack": "10.0.3",
"ajv": "6.12.2",
"autoprefixer": "9.8.0",
"babel-loader": "8.1.0",
@@ -88,9 +88,9 @@
}
},
"@angular-devkit/build-optimizer": {
"version": "0.1000.2",
"resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.1000.2.tgz",
"integrity": "sha512-wbrgJQw92+A7kFaG7U0F9MMzhVI32tcIdr26+SFXWGAeBaWIkBfMs/jfGLlEYESLqQQF5oMn7LJBwXu+nkPHvw==",
"version": "0.1000.3",
"resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.1000.3.tgz",
"integrity": "sha512-6mFoubg08UCWC0fE2mGoawEt2R1VlGStvUNAP2PRCjoj1ZySa1NnVYoKk65cyAAA3K2o7vSoDZesNq1uABjZbg==",
"dev": true,
"requires": {
"loader-utils": "2.0.0",
@@ -100,20 +100,20 @@
}
},
"@angular-devkit/build-webpack": {
"version": "0.1000.2",
"resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1000.2.tgz",
"integrity": "sha512-x1fHnZFTwvAE3lB6XnlJmf0KNiiAsZKGdUuTXqzgsgh34A/aFOWtu0EB6cw6lvifMj1ioDT8Zjp8N89Lh5AtEA==",
"version": "0.1000.3",
"resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1000.3.tgz",
"integrity": "sha512-+vmn9d9THFubSWS28K1+nElUfOrhT576ptVZMd0a5S24momV8loW3J8iBOBfnGal/P86ZCAyP46kSirlAzH9Jg==",
"dev": true,
"requires": {
"@angular-devkit/architect": "0.1000.2",
"@angular-devkit/core": "10.0.2",
"@angular-devkit/architect": "0.1000.3",
"@angular-devkit/core": "10.0.3",
"rxjs": "6.5.5"
}
},
"@angular-devkit/core": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-10.0.2.tgz",
"integrity": "sha512-gD8iUP28GscsHqGKKu+NtX97bt7aXDZmIYqWTv4SThrcsPYY2A4tBw+NBbNAwjHkNfn4jflpqTmcN9gBAoLoSg==",
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-10.0.3.tgz",
"integrity": "sha512-m27ogjq44j80x64RnEswSvy8UewUqeCVJBbEuY6fzrWoaiCf12sgPlrSCwjwfhtQrLgl1e/i9zYA7U6ulGRXyg==",
"dev": true,
"requires": {
"ajv": "6.12.2",
@@ -124,28 +124,28 @@
}
},
"@angular-devkit/schematics": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-10.0.2.tgz",
"integrity": "sha512-BUUWAreHoxk4Z91Xhr+wtFUhK6+7AOczsIxlZmJnQwSUhN2ZdiDjOXeO3NFkDdL8CtNOz5khGu2iNBqn08FpUw==",
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-10.0.3.tgz",
"integrity": "sha512-TjA2ZSPCgUK9l4FiRTIQY7DceXMAvNzOMWffy9o3kv2HPtxG9kuBrQXk++Z99zpylK0cAsugV7t/5ANpUkrIiA==",
"dev": true,
"requires": {
"@angular-devkit/core": "10.0.2",
"@angular-devkit/core": "10.0.3",
"ora": "4.0.4",
"rxjs": "6.5.5"
}
},
"@angular/animations": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/@angular/animations/-/animations-10.0.3.tgz",
"integrity": "sha512-s7hob0TmSRqsgEWdB0EYsKY8eF8iD6Sj44XntecAhEc/IxVQGIIZiNwGvW43Lb8iEdbvdF+GJfgxu5I8ZWMX3Q==",
"version": "10.0.4",
"resolved": "https://registry.npmjs.org/@angular/animations/-/animations-10.0.4.tgz",
"integrity": "sha512-UzQiWhDHY6wixS1Nh+Jwpzq1weiLGXJPt3Pa4pETpt3Hg7MIUu62dik6OFWuGYQPbn9DJYH+CH+sRxN1GCVjww==",
"requires": {
"tslib": "^2.0.0"
}
},
"@angular/cdk": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-10.0.2.tgz",
"integrity": "sha512-ZvZkeh7qXllAGSOFvWSYurCslflTmB0JD3gonmUKOBl/O/AcOTPntP+iOrUaC3+eR3ohsfL5SswxChW0NF+oHQ==",
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-10.1.0.tgz",
"integrity": "sha512-zSZcpsfhRWdNAzNXnKZIlaX1uAWY+8W2zV7ktQNJoNypo9X02rY0YtmPBzlPjT0ITjM4EqohZ07nfd+5bLUw4A==",
"requires": {
"parse5": "^5.0.0",
"tslib": "^2.0.0"
@@ -160,16 +160,16 @@
}
},
"@angular/cli": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-10.0.2.tgz",
"integrity": "sha512-L/uLUrZNIwbYzIeU9R3SC2hblDgtxP57msmRjoOQBpSzwlOME+z0wlCXPv+h9NOzNPvVVbEtLtjBgZxUw0IHzg==",
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-10.0.3.tgz",
"integrity": "sha512-ONK8YG20KuakQetY0lPKDAOA3uBoLurdpSfFspFkcECyDimwJYSEydi3FUnCxEexeoKvrQWcol+q+u9YPoHCyg==",
"dev": true,
"requires": {
"@angular-devkit/architect": "0.1000.2",
"@angular-devkit/core": "10.0.2",
"@angular-devkit/schematics": "10.0.2",
"@schematics/angular": "10.0.2",
"@schematics/update": "0.1000.2",
"@angular-devkit/architect": "0.1000.3",
"@angular-devkit/core": "10.0.3",
"@angular-devkit/schematics": "10.0.3",
"@schematics/angular": "10.0.3",
"@schematics/update": "0.1000.3",
"@yarnpkg/lockfile": "1.1.0",
"ansi-colors": "4.1.1",
"debug": "4.1.1",
@@ -202,25 +202,25 @@
}
},
"@angular/common": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/@angular/common/-/common-10.0.3.tgz",
"integrity": "sha512-R2q/Vt07PHgcmvZBVGcYjf6K2xERCHWUYQYN1HsgjVQUu5ypvE7Kqs+6s0BfIoBKc+ejKmjMHHumnm+89O+gXg==",
"version": "10.0.4",
"resolved": "https://registry.npmjs.org/@angular/common/-/common-10.0.4.tgz",
"integrity": "sha512-9DJMD8GgHz7i2fMz0f1IHZlDSIz83uE6fcH8SIq1iCSWT2dubRRpCX000VpIyhAgfkCgdNCYXQ7VGNsZceoagQ==",
"requires": {
"tslib": "^2.0.0"
}
},
"@angular/compiler": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-10.0.3.tgz",
"integrity": "sha512-SmzMYxBprs8bVS9WctiCDj6KVp3jZFEaxGTbC/FwtdvesMIdOktpHggUeJW+OzUTwTnYVmKrm6d8rdg3QSaXFQ==",
"version": "10.0.4",
"resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-10.0.4.tgz",
"integrity": "sha512-1rnEmSHJtrKC1QD+PyF36xwMnSqG4Slgi5+PYk3BxIa5vbWBibrYijtd/uCNhscfPSpfb06MVM2mRsrc+BmbQg==",
"requires": {
"tslib": "^2.0.0"
}
},
"@angular/compiler-cli": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-10.0.3.tgz",
"integrity": "sha512-XK2xQX0RLr7QMkEseDhcdqZ2hMM5n1Q6LFvOJfxQXXBpa7DBC9mB6HLsn0vrLgwaAfz+SEQ7pLDgXQSy2tmJUg==",
"version": "10.0.4",
"resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-10.0.4.tgz",
"integrity": "sha512-uZKk6Ab4Pw8qcaXhpORuEoCbPSHWx3TWcs9OXIKIhzOOoMMe9OSt2SzOkHCrySSaik1IhQODnHww7sGRw5mxwQ==",
"dev": true,
"requires": {
"canonical-path": "1.0.0",
@@ -401,49 +401,57 @@
}
},
"@angular/core": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/@angular/core/-/core-10.0.3.tgz",
"integrity": "sha512-EfWAz5StlPYo2ZtvVzeoNlGrFAXRncwGd/CExbLFOZx4HcDXVkATw5d4vnKHmmKacDqnbuvMD2M0Tl0EJi5q4g==",
"version": "10.0.4",
"resolved": "https://registry.npmjs.org/@angular/core/-/core-10.0.4.tgz",
"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": {
"tslib": "^2.0.0"
}
},
"@angular/forms": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/@angular/forms/-/forms-10.0.3.tgz",
"integrity": "sha512-08XlERBGVnzea4sVY7J1JsU6zX/ENGZGB9V4K1jpX6gNjlAk2AbskC76+ngdsgdzv0neNEqPoLdMAZerNECnUg==",
"version": "10.0.4",
"resolved": "https://registry.npmjs.org/@angular/forms/-/forms-10.0.4.tgz",
"integrity": "sha512-SJSYZCfHua9fi/dks1q+ad9OGBblRUn3Q1V4B7r99fJYr39qRiIHcegikhY4h8H3Wk1bJRGJG7iXmxJhjWXK3Q==",
"requires": {
"tslib": "^2.0.0"
}
},
"@angular/material": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/@angular/material/-/material-10.0.2.tgz",
"integrity": "sha512-xG8lCG+QS+r61aDoBauH6RyNuOHai4yxhn3e8cb2ua86liarJmF9jqlW0tB49tE1ZLz9U/+ybJKkos2kX1eF1Q==",
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/@angular/material/-/material-10.1.0.tgz",
"integrity": "sha512-zHJxMHYAyfJbhXGhsWUFTABBBQVzWNexuJGWh19MQx0jQn7aLek5nYQ0oLG00+ArISVAg/XMOtnbdRaemFWVzw==",
"requires": {
"tslib": "^2.0.0"
}
},
"@angular/platform-browser": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-10.0.3.tgz",
"integrity": "sha512-f6JsFMunJNn7fPtwwWbZsXZ/JFA5RlwbyHKKkLAPMLLJwabOcSh/bUpPWKoRMHpUxr53PGEX4XY6QNPJXrUaag==",
"version": "10.0.4",
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-10.0.4.tgz",
"integrity": "sha512-iaZ8pFS5XUgPCO6/C47TzSFPzlzgleayq099cVOOx9z0t/SwUCSKt4AdAVhyQ8RTnx6l1JmmwBgRaXpScZlqzg==",
"requires": {
"tslib": "^2.0.0"
}
},
"@angular/platform-browser-dynamic": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-10.0.3.tgz",
"integrity": "sha512-ASZWymDVCgmDe0XE1djGKrfJnUR65PdfoZ51CQ7xSVJTnXp6kCAXzFeG2IyqU+O7IXvQRgvb4GOA4Y6GScNVKw==",
"version": "10.0.4",
"resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-10.0.4.tgz",
"integrity": "sha512-RoUMqYhUwF6+Mvk/aH0IZQ1D0SDEi9k5EZlx9CJ3RvNuKygk7to+S4vMWVpGxFQlwdS3bytRLKi+Kki6f4nLkg==",
"requires": {
"tslib": "^2.0.0"
}
},
"@angular/router": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/@angular/router/-/router-10.0.3.tgz",
"integrity": "sha512-WMNJ4yS3xvgOPa73hKQNHoTCT2l+bvompxdqZSqN7dh92QtPJBXCm+qBC2jRDj4wgP7Eq5dgymh7a/dZqseFEQ==",
"version": "10.0.4",
"resolved": "https://registry.npmjs.org/@angular/router/-/router-10.0.4.tgz",
"integrity": "sha512-iDLWdmltU5pZ6M/fBKC5Kg2o9Aqb1YJ+oHXFu186BQAl2RNeNCmMQ0VaCxjpMgD/MoSxpuRuGQ6rRrCSFCxtcQ==",
"requires": {
"tslib": "^2.0.0"
}
@@ -1556,12 +1564,12 @@
}
},
"@ngtools/webpack": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-10.0.2.tgz",
"integrity": "sha512-Py8jkc6UIHtp5TKKAMkNiKhx0goL+d7RkQEBWIvO+9e5fBGIt0Npy3dBoJ9gRldaGIjLZWlHhGsgeaYbq5dlvA==",
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-10.0.3.tgz",
"integrity": "sha512-0TuvYMCLtsApLtCHXeDBYGEoAQXzsRLpgFxPM5W7CGcj0ecthZO4NYrMAt+J8ky//KmbxqQSFHWmss2cbirIPA==",
"dev": true,
"requires": {
"@angular-devkit/core": "10.0.2",
"@angular-devkit/core": "10.0.3",
"enhanced-resolve": "4.1.1",
"rxjs": "6.5.5",
"webpack-sources": "1.4.3"
@@ -1611,23 +1619,23 @@
}
},
"@schematics/angular": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-10.0.2.tgz",
"integrity": "sha512-viSf1HQH2vxZAonkfdAjJ/0Z8VgKptsi4UYtJDwabKRbbyp2EQ/vhEPI/ddV4QgrQqR8mkOl7nu8JqL2M0+v6A==",
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-10.0.3.tgz",
"integrity": "sha512-Or2pCqjpPbAvmbxtfMosGwQbNbSL4xodK5Key7678ZAPGB+rcxrVkBI9yxEJ/qzF/LrmMoKqy0JCmVLK7Grpog==",
"dev": true,
"requires": {
"@angular-devkit/core": "10.0.2",
"@angular-devkit/schematics": "10.0.2"
"@angular-devkit/core": "10.0.3",
"@angular-devkit/schematics": "10.0.3"
}
},
"@schematics/update": {
"version": "0.1000.2",
"resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.1000.2.tgz",
"integrity": "sha512-6PSJ+WexBqY0ESo0Kp6fa9wPWAXKE9oyLNjISJ1S9QKCVowoHa8FV+7BalVOUYwUhnUzwPCF6n7PqcJiZR632g==",
"version": "0.1000.3",
"resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.1000.3.tgz",
"integrity": "sha512-Nncdklmzi1tyzkoAh7GlSslxriRhftlmfqPVmFHrrPRttYACtT/QH5qcWsrPgTPpHGINYEHrPjpeljsMoMchBQ==",
"dev": true,
"requires": {
"@angular-devkit/core": "10.0.2",
"@angular-devkit/schematics": "10.0.2",
"@angular-devkit/core": "10.0.3",
"@angular-devkit/schematics": "10.0.3",
"@yarnpkg/lockfile": "1.1.0",
"ini": "1.3.5",
"npm-package-arg": "^8.0.0",
@@ -2899,9 +2907,9 @@
}
},
"caniuse-lite": {
"version": "1.0.30001100",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001100.tgz",
"integrity": "sha512-0eYdp1+wFCnMlCj2oudciuQn2B9xAFq3WpgpcBIZTxk/1HNA/O2YA7rpeYhnOqsqAJq1AHUgx6i1jtafg7m2zA==",
"version": "1.0.30001104",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001104.tgz",
"integrity": "sha512-pkpCg7dmI/a7WcqM2yfdOiT4Xx5tzyoHAXWsX5/HxZ3TemwDZs0QXdqbE0UPLPVy/7BeK7693YfzfRYfu1YVpg==",
"dev": true
},
"canonical-path": {
@@ -3027,9 +3035,9 @@
}
},
"cli-spinners": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.3.0.tgz",
"integrity": "sha512-Xs2Hf2nzrvJMFKimOR7YR0QwZ8fc0u98kdtwN1eNAZzNQgH3vK2pXzff6GJtKh7S5hoJ87ECiAiZFS2fb5Ii2w==",
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.4.0.tgz",
"integrity": "sha512-sJAofoarcm76ZGpuooaO0eDy8saEy+YoZBLjC4h8srt4jeBnkYeOgqxgsJQTpyt2LjI5PTfLJHSL+41Yu4fEJA==",
"dev": true
},
"cli-width": {
@@ -4324,9 +4332,9 @@
"dev": true
},
"electron-to-chromium": {
"version": "1.3.498",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.498.tgz",
"integrity": "sha512-W1hGwaQEU8j9su2jeAr3aabkPuuXw+j8t73eajGAkEJWbfWiwbxBwQN/8Qmv2qCy3uCDm2rOAaZneYQM8VGC4w==",
"version": "1.3.501",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.501.tgz",
"integrity": "sha512-tyzuKaV2POw2mtqBBzQGNBojMZzH0MRu8bT8T/50x+hWeucyG/9pkgAATy+PcM2ySNM9+8eG2VllY9c6j4i+bg==",
"dev": true
},
"elliptic": {
@@ -6990,9 +6998,9 @@
"dev": true
},
"less": {
"version": "3.12.0",
"resolved": "https://registry.npmjs.org/less/-/less-3.12.0.tgz",
"integrity": "sha512-3mmSHFRP9hGxxQgAKgChfau1LO3ksV/zyZf1qd2ENyBV778NA9Ids99wFRA20jE+5prT7oScKod8PoGlxSe1gg==",
"version": "3.12.2",
"resolved": "https://registry.npmjs.org/less/-/less-3.12.2.tgz",
"integrity": "sha512-+1V2PCMFkL+OIj2/HrtrvZw0BC0sYLMICJfbQjuj/K8CEnlrFX6R5cKKgzzttsZDHyxQNL1jqMREjKN3ja/E3Q==",
"dev": true,
"requires": {
"errno": "^0.1.1",
@@ -7687,9 +7695,9 @@
}
},
"native-request": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/native-request/-/native-request-1.0.5.tgz",
"integrity": "sha512-7wU3DvBGAJQxWuMR3F62zrhB7hxNj2DdlC/eBVrCgavc6+ZpFZOqS/PsR7QyUPLMkFk0GvvzoeeOAZGLLnObnA==",
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/native-request/-/native-request-1.0.7.tgz",
"integrity": "sha512-9nRjinI9bmz+S7dgNtf4A70+/vPhnd+2krGpy4SUlADuOuSa24IDkNaZ+R/QT1wQ6S8jBdi6wE7fLekFZNfUpQ==",
"dev": true,
"optional": true
},
@@ -8692,9 +8700,9 @@
}
},
"portfinder": {
"version": "1.0.26",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.26.tgz",
"integrity": "sha512-Xi7mKxJHHMI3rIUrnm/jjUgwhbYMkp/XKEcZX3aG4BrumLpq3nmoQMX+ClYnDZnZ/New7IatC1no5RX0zo1vXQ==",
"version": "1.0.27",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.27.tgz",
"integrity": "sha512-bJ3U3MThKnyJ9Dx1Idtm5pQmxXqw08+XOHhi/Lie8OF1OlhVaBFhsntAIhkZYjfDcCzszSr0w1yCbccThhzgxQ==",
"dev": true,
"requires": {
"async": "^2.6.2",
@@ -12018,9 +12026,9 @@
"dev": true
},
"typescript": {
"version": "3.9.6",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.6.tgz",
"integrity": "sha512-Pspx3oKAPJtjNwE92YS05HQoY7z2SFyOpHo9MqJor3BXAGNaPUs83CuVp9VISFkSjyRfiTpmKuAYGJB7S7hOxw==",
"version": "3.9.7",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz",
"integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==",
"dev": true
},
"ua-parser-js": {

View File

@@ -11,28 +11,29 @@
},
"private": true,
"dependencies": {
"@angular/animations": "~10.0.3",
"@angular/cdk": "^10.0.2",
"@angular/common": "~10.0.3",
"@angular/compiler": "~10.0.3",
"@angular/core": "~10.0.3",
"@angular/forms": "~10.0.3",
"@angular/material": "^10.0.2",
"@angular/platform-browser": "~10.0.3",
"@angular/platform-browser-dynamic": "~10.0.3",
"@angular/router": "~10.0.3",
"@angular/animations": "^10.0.4",
"@angular/cdk": "^10.1.0",
"@angular/common": "^10.0.4",
"@angular/compiler": "^10.0.4",
"@angular/core": "^10.0.4",
"@angular/flex-layout": "^10.0.0-beta.32",
"@angular/forms": "^10.0.4",
"@angular/material": "^10.1.0",
"@angular/platform-browser": "^10.0.4",
"@angular/platform-browser-dynamic": "^10.0.4",
"@angular/router": "^10.0.4",
"rxjs": "~6.5.5",
"socket.io": "^2.3.0",
"tslib": "^2.0.0",
"zone.js": "~0.10.3"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.1000.2",
"@angular/cli": "~10.0.2",
"@angular/compiler-cli": "~10.0.3",
"@types/node": "^12.11.1",
"@angular-devkit/build-angular": "^0.1000.3",
"@angular/cli": "^10.0.3",
"@angular/compiler-cli": "^10.0.4",
"@types/jasmine": "~3.5.0",
"@types/jasminewd2": "~2.0.3",
"@types/node": "^12.11.1",
"codelyzer": "^6.0.0",
"jasmine-core": "~3.5.0",
"jasmine-spec-reporter": "~5.0.0",
@@ -44,6 +45,6 @@
"protractor": "~7.0.0",
"ts-node": "~8.3.0",
"tslint": "~6.1.0",
"typescript": "~3.9.5"
"typescript": "^3.9.7"
}
}

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

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

View File

@@ -0,0 +1,7 @@
import { AuthGuard } from './auth.guard';
describe('Auth.Guard', () => {
it('should create an instance', () => {
expect(new AuthGuard()).toBeTruthy();
});
});

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

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

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

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

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

View File

@@ -0,0 +1,7 @@
import { PasswordErrorStateMatcher } from './password-error-state-matcher';
describe('PasswordErrorStateMatcher', () => {
it('should create an instance', () => {
expect(new PasswordErrorStateMatcher()).toBeTruthy();
});
});

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

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

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

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

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

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

@@ -0,0 +1,6 @@
export class User {
id: number;
username: string;
email: string;
token: string;
}

View File

@@ -1,8 +1,17 @@
import { NgModule } from '@angular/core';
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({
imports: [RouterModule.forRoot(routes)],

View File

@@ -16,69 +16,6 @@ svg.material-icons:not(:last-child) {
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 */
@media screen and (max-width: 767px) {
@@ -93,6 +30,10 @@ svg.material-icons:not(:last-child) {
}
.router {
height: 100%;
}
.chat {
float: right;
height: 100%;

View File

@@ -1,20 +1,3 @@
<div class="chat">
<app-chat></app-chat>
<div class="router">
<router-outlet></router-outlet>
</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>

View File

@@ -1,6 +1,6 @@
import { Component } from '@angular/core';
import { SocketService } from './socket/socket.service';
import { HttpClient } from '@angular/common/http';
import { AccountService } from './account/account.service';
@Component({
selector: 'app-root',
@@ -10,22 +10,14 @@ import { HttpClient } from '@angular/common/http';
export class AppComponent {
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 httpService
*/
constructor(private socketService: SocketService,
private httpService: HttpClient) { }
constructor(private accountService: AccountService,
private socketService: SocketService,
) { }
}

View File

@@ -1,32 +1,50 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
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 { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ChatComponent } from './chat/chat.component';
import { EntryComponent } from './chat/entry/entry.component';
import { InputComponent } from './chat/input/input.component';
import {MatCardModule} from '@angular/material/card';
import {MatInputModule} from '@angular/material/input';
import { LoginComponent } from './account/login/login.component';
import { TestComponent } from './test/test.component';
import { RegisterComponent } from './account/register/register.component';
import { fakeBackendProvider } from './utils/fake-backend';
@NgModule({
declarations: [
AppComponent,
ChatComponent,
EntryComponent,
InputComponent
InputComponent,
LoginComponent,
TestComponent,
RegisterComponent
],
imports: [
BrowserModule,
HttpClientModule,
AppRoutingModule,
BrowserModule,
BrowserAnimationsModule,
FlexLayoutModule,
MatButtonModule,
MatCardModule,
MatInputModule
MatIconModule,
MatInputModule,
ReactiveFormsModule,
AppRoutingModule,
],
providers: [
fakeBackendProvider,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

View File

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

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

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

View File

@@ -0,0 +1,7 @@
import { FakeBackend } from './fake-backend';
describe('FakeBackend', () => {
it('should create an instance', () => {
expect(new FakeBackend()).toBeTruthy();
});
});

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

View File

@@ -3,7 +3,8 @@
// The list of file replacements can be found in `angular.json`.
export const environment = {
production: false
production: false,
apiUrl: 'http://localhost:4200',
};
/*

View File

@@ -10,6 +10,6 @@
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<app-root></app-root>
<app-root></app-root>
</body>
</html>