diff --git a/package-lock.json b/package-lock.json index 762c5b7..321d919 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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": { diff --git a/package.json b/package.json index 5f88dc1..12d7b78 100644 --- a/package.json +++ b/package.json @@ -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" } } diff --git a/src/app/account/account.service.spec.ts b/src/app/account/account.service.spec.ts new file mode 100644 index 0000000..2ffad6f --- /dev/null +++ b/src/app/account/account.service.spec.ts @@ -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(); + }); +}); diff --git a/src/app/account/account.service.ts b/src/app/account/account.service.ts new file mode 100644 index 0000000..eb17991 --- /dev/null +++ b/src/app/account/account.service.ts @@ -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; + public user: Observable; + + constructor(private httpClient: HttpClient) { + this.userSubject = new BehaviorSubject(JSON.parse(localStorage.getItem('user'))); + this.user = this.userSubject.asObservable(); + } + + public get userValue() { + return this.userSubject.value; + } + + login(username, password) { + return this.httpClient.post(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(environment.apiUrl + '/fake_registration', user); + } + +} diff --git a/src/app/account/auth.guard.spec.ts b/src/app/account/auth.guard.spec.ts new file mode 100644 index 0000000..7207e37 --- /dev/null +++ b/src/app/account/auth.guard.spec.ts @@ -0,0 +1,7 @@ +import { AuthGuard } from './auth.guard'; + +describe('Auth.Guard', () => { + it('should create an instance', () => { + expect(new AuthGuard()).toBeTruthy(); + }); +}); diff --git a/src/app/account/auth.guard.ts b/src/app/account/auth.guard.ts new file mode 100644 index 0000000..bb7a40a --- /dev/null +++ b/src/app/account/auth.guard.ts @@ -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; + } +} + diff --git a/src/app/account/login/login.component.css b/src/app/account/login/login.component.css new file mode 100644 index 0000000..1427fe0 --- /dev/null +++ b/src/app/account/login/login.component.css @@ -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; +} diff --git a/src/app/account/login/login.component.html b/src/app/account/login/login.component.html new file mode 100644 index 0000000..cb46847 --- /dev/null +++ b/src/app/account/login/login.component.html @@ -0,0 +1,30 @@ + diff --git a/src/app/account/login/login.component.spec.ts b/src/app/account/login/login.component.spec.ts new file mode 100644 index 0000000..d6d85a8 --- /dev/null +++ b/src/app/account/login/login.component.spec.ts @@ -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; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ LoginComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LoginComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/account/login/login.component.ts b/src/app/account/login/login.component.ts new file mode 100644 index 0000000..ae12d92 --- /dev/null +++ b/src/app/account/login/login.component.ts @@ -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 { + } + +} diff --git a/src/app/account/register/password-error-state-matcher.spec.ts b/src/app/account/register/password-error-state-matcher.spec.ts new file mode 100644 index 0000000..75a6610 --- /dev/null +++ b/src/app/account/register/password-error-state-matcher.spec.ts @@ -0,0 +1,7 @@ +import { PasswordErrorStateMatcher } from './password-error-state-matcher'; + +describe('PasswordErrorStateMatcher', () => { + it('should create an instance', () => { + expect(new PasswordErrorStateMatcher()).toBeTruthy(); + }); +}); diff --git a/src/app/account/register/password-error-state-matcher.ts b/src/app/account/register/password-error-state-matcher.ts new file mode 100644 index 0000000..12aa1a9 --- /dev/null +++ b/src/app/account/register/password-error-state-matcher.ts @@ -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; + } +} diff --git a/src/app/account/register/register.component.css b/src/app/account/register/register.component.css new file mode 100644 index 0000000..5a4c07c --- /dev/null +++ b/src/app/account/register/register.component.css @@ -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; +} diff --git a/src/app/account/register/register.component.html b/src/app/account/register/register.component.html new file mode 100644 index 0000000..4dbb748 --- /dev/null +++ b/src/app/account/register/register.component.html @@ -0,0 +1,48 @@ +
+ + Sign up + +
+ + User name + + + + + Email + + + +
+ + Password + + + + + Confirm password + + Passwords don't match. + +
+ +
+ + Login +
+
+
+
+
diff --git a/src/app/account/register/register.component.spec.ts b/src/app/account/register/register.component.spec.ts new file mode 100644 index 0000000..6c19551 --- /dev/null +++ b/src/app/account/register/register.component.spec.ts @@ -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; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ RegisterComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(RegisterComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/account/register/register.component.ts b/src/app/account/register/register.component.ts new file mode 100644 index 0000000..dc1c587 --- /dev/null +++ b/src/app/account/register/register.component.ts @@ -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 { } +} diff --git a/src/app/account/user.spec.ts b/src/app/account/user.spec.ts new file mode 100644 index 0000000..ba0576c --- /dev/null +++ b/src/app/account/user.spec.ts @@ -0,0 +1,7 @@ +import { User } from './user'; + +describe('User', () => { + it('should create an instance', () => { + expect(new User()).toBeTruthy(); + }); +}); diff --git a/src/app/account/user.ts b/src/app/account/user.ts new file mode 100644 index 0000000..423f82b --- /dev/null +++ b/src/app/account/user.ts @@ -0,0 +1,6 @@ +export class User { + id: number; + username: string; + email: string; + token: string; +} diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 06c7342..d237669 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -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)], diff --git a/src/app/app.component.css b/src/app/app.component.css index e32d84b..7ca0330 100644 --- a/src/app/app.component.css +++ b/src/app/app.component.css @@ -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%; diff --git a/src/app/app.component.html b/src/app/app.component.html index 9d689f5..ae41dd8 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,20 +1,3 @@ -
- +
+
- -
-
-
- - - Send test message -
- -
- - - Call rest api -
-
-
- diff --git a/src/app/app.component.ts b/src/app/app.component.ts index ab75af0..f34dff4 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -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, + ) { } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 9d7f9ad..ed2613b 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -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: [ + HttpClientModule, + BrowserModule, + BrowserAnimationsModule, + FlexLayoutModule, + MatButtonModule, + MatCardModule, + MatIconModule, + MatInputModule, + ReactiveFormsModule, + AppRoutingModule, + ], + providers: [ + fakeBackendProvider, ], - imports: [ - BrowserModule, - HttpClientModule, - AppRoutingModule, - BrowserAnimationsModule, - MatCardModule, - MatInputModule - ], - providers: [], bootstrap: [AppComponent] }) export class AppModule { } diff --git a/src/app/test/test.component.css b/src/app/test/test.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/test/test.component.html b/src/app/test/test.component.html new file mode 100644 index 0000000..08fe1cd --- /dev/null +++ b/src/app/test/test.component.html @@ -0,0 +1,15 @@ +
+
+
+ + + Send test message +
+ +
+ + + Call rest api +
+
+
diff --git a/src/app/test/test.component.spec.ts b/src/app/test/test.component.spec.ts new file mode 100644 index 0000000..ef4e38c --- /dev/null +++ b/src/app/test/test.component.spec.ts @@ -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; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ TestComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(TestComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/test/test.component.ts b/src/app/test/test.component.ts new file mode 100644 index 0000000..2d9218e --- /dev/null +++ b/src/app/test/test.component.ts @@ -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 { + } + +} diff --git a/src/app/utils/fake-backend.spec.ts b/src/app/utils/fake-backend.spec.ts new file mode 100644 index 0000000..ac1e6af --- /dev/null +++ b/src/app/utils/fake-backend.spec.ts @@ -0,0 +1,7 @@ +import { FakeBackend } from './fake-backend'; + +describe('FakeBackend', () => { + it('should create an instance', () => { + expect(new FakeBackend()).toBeTruthy(); + }); +}); diff --git a/src/app/utils/fake-backend.ts b/src/app/utils/fake-backend.ts new file mode 100644 index 0000000..dc0a847 --- /dev/null +++ b/src/app/utils/fake-backend.ts @@ -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, next: HttpHandler): Observable> { + 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, +} diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 7b4f817..42899ff 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -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', }; /* diff --git a/src/index.html b/src/index.html index 1bcbc5d..0ece884 100644 --- a/src/index.html +++ b/src/index.html @@ -10,6 +10,6 @@ - +