diff --git a/.all-contributorsrc b/.all-contributorsrc new file mode 100644 index 00000000..679b755c --- /dev/null +++ b/.all-contributorsrc @@ -0,0 +1,101 @@ +{ + "projectName": "angular-example-app", + "projectOwner": "Ismaestro", + "files": ["README.md"], + "commitType": "docs", + "commitConvention": "angular", + "contributorsPerLine": 6, + "contributors": [ + { + "login": "magicalyak", + "name": "Tom Gamull", + "avatar_url": "https://avatars.githubusercontent.com/u/6165889?v=4", + "profile": "https://magicalyak.org/", + "contributions": ["infra"] + }, + { + "login": "mansya", + "name": "mansyaprime", + "avatar_url": "https://avatars.githubusercontent.com/u/33461607?v=4", + "profile": "https://github.com/mansya", + "contributions": ["code"] + }, + { + "login": "codeimmortal", + "name": "codeimmortal", + "avatar_url": "https://avatars.githubusercontent.com/u/16804408?v=4", + "profile": "https://github.com/codeimmortal", + "contributions": ["code"] + }, + { + "login": "tomasfse", + "name": "tomasfse", + "avatar_url": "https://avatars.githubusercontent.com/u/22914697?v=4", + "profile": "https://github.com/tomasfse", + "contributions": ["code"] + }, + { + "login": "golu7679", + "name": "golu", + "avatar_url": "https://avatars.githubusercontent.com/u/55990159?v=4", + "profile": "https://golu7679.github.io/", + "contributions": ["code"] + }, + { + "login": "v-rr", + "name": "rancyr", + "avatar_url": "https://avatars.githubusercontent.com/u/90811840?v=4", + "profile": "https://github.com/microsoft/Secure-Supply-Chain/", + "contributions": ["code"] + }, + { + "login": "codingphasedotcom", + "name": "codingphasedotcom", + "avatar_url": "https://avatars.githubusercontent.com/u/26421899?v=4", + "profile": "http://www.codingphase.com/", + "contributions": ["code"] + }, + { + "login": "scip92", + "name": "Max", + "avatar_url": "https://avatars.githubusercontent.com/u/15237896?v=4", + "profile": "https://github.com/scip92", + "contributions": ["code"] + }, + { + "login": "HerbertKarajan", + "name": "Karajan", + "avatar_url": "https://avatars.githubusercontent.com/u/20851191?v=4", + "profile": "https://github.com/HerbertKarajan", + "contributions": ["code"] + }, + { + "login": "carlchandev", + "name": "Carl Chan", + "avatar_url": "https://avatars.githubusercontent.com/u/34772941?v=4", + "profile": "https://github.com/carlchandev", + "contributions": ["code"] + }, + { + "login": "dyeimys", + "name": "Dyeimys Franco Correa", + "avatar_url": "https://avatars.githubusercontent.com/u/4250372?v=4", + "profile": "https://github.com/dyeimys", + "contributions": ["code"] + }, + { + "login": "mugan86", + "name": "Anartz Mugika Ledo", + "avatar_url": "https://avatars.githubusercontent.com/u/5081970?v=4", + "profile": "https://anartz-mugika.com/qwik-book/es/", + "contributions": ["code"] + }, + { + "login": "OrlPep", + "name": "OrlPep", + "avatar_url": "https://avatars.githubusercontent.com/u/171474908?v=4", + "profile": "https://github.com/OrlPep", + "contributions": ["code"] + } + ] +} diff --git a/.browserslistrc b/.browserslistrc old mode 100644 new mode 100755 index 4f9ac269..525da03c --- a/.browserslistrc +++ b/.browserslistrc @@ -8,9 +8,7 @@ # You can see what browsers were selected by your queries by running: # npx browserslist -last 1 Chrome version -last 1 Firefox version -last 2 Edge major versions -last 2 Safari major versions -last 2 iOS major versions -Firefox ESR +last 2 Chrome versions +last 2 Firefox versions +last 2 Edge versions +last 2 Safari versions diff --git a/.editorconfig b/.editorconfig old mode 100644 new mode 100755 index 59d9a3a3..b040ca86 --- a/.editorconfig +++ b/.editorconfig @@ -5,6 +5,7 @@ root = true charset = utf-8 indent_style = space indent_size = 2 +end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true @@ -12,5 +13,8 @@ trim_trailing_whitespace = true quote_type = single [*.md] -max_line_length = off +insert_final_newline = false trim_trailing_whitespace = false + +[*.xlf] +insert_final_newline = false diff --git a/.eslintignore b/.eslintignore deleted file mode 100755 index 3e825fbe..00000000 --- a/.eslintignore +++ /dev/null @@ -1,8 +0,0 @@ -.idea -node_modules -documentation -cypress/videos -cypress/screenshots -.vscode -*.d.ts -*.js diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 99b4d9ed..00000000 --- a/.eslintrc.json +++ /dev/null @@ -1,167 +0,0 @@ -{ - "root": true, - "ignorePatterns": [ - "projects/**/*" - ], - "overrides": [ - { - "files": [ - "*.ts" - ], - "parserOptions": { - "project": [ - "tsconfig.json", - "e2e/tsconfig.json" - ], - "createDefaultProgram": true - }, - "extends": [ - "plugin:@angular-eslint/ng-cli-compat", - "plugin:@angular-eslint/ng-cli-compat--formatting-add-on", - "plugin:@angular-eslint/template/process-inline-templates" - ], - "plugins": [ - "sonarjs" - ], - "rules": { - "@angular-eslint/component-selector": [ - "error", - { - "type": "element", - "prefix": "app", - "style": "kebab-case" - } - ], - "@angular-eslint/directive-selector": [ - "error", - { - "type": "attribute", - "prefix": "app", - "style": "camelCase" - } - ], - "@typescript-eslint/await-thenable": "error", - "@typescript-eslint/ban-types": [ - "error", - { - "types": { - "String": { - "message": "Use string instead", - "fixWith": "string" - }, - "Boolean": { - "message": "Use boolean instead", - "fixWith": "boolean" - }, - "Number": { - "message": "Use number instead", - "fixWith": "number" - } - } - } - ], - "@typescript-eslint/consistent-type-definitions": "error", - "@typescript-eslint/dot-notation": "off", - "@typescript-eslint/explicit-member-accessibility": [ - "off", - { - "accessibility": "explicit" - } - ], - "@typescript-eslint/no-extra-semi": "error", - "@typescript-eslint/no-for-in-array": "error", - "@typescript-eslint/no-unnecessary-type-assertion": "error", - "@typescript-eslint/no-use-before-define": "off", - "@typescript-eslint/require-array-sort-compare": [ - "error", - { - "ignoreStringArrays": true - } - ], - "brace-style": [ - "error", - "1tbs", - { "allowSingleLine": true } - ], - "default-case-last": "error", - "dot-notation": "off", - "id-denylist": "off", - "id-match": "off", - "complexity": ["error", { "max": 6 }], - "max-len": [ - "error", - { - "code": 180 - } - ], - "max-lines-per-function": [ - "error", - { - "max": 300 - } - ], - "max-params": [ - "error", - { - "max": 10 - } - ], - "no-empty-function": "off", - "no-empty-pattern": "error", - "no-extra-semi": "error", - "no-multi-str": "off", - "no-self-assign": "error", - "no-shadow": "off", - "no-underscore-dangle": "off", - "no-unused-expressions": ["error", { "allowTernary": true }], - "no-use-before-define": "off", - "semi": "off", - "sonarjs/cognitive-complexity": "error", - "sonarjs/max-switch-cases": "error", - "sonarjs/no-all-duplicated-branches": "error", - "sonarjs/no-collapsible-if": "error", - "sonarjs/no-collection-size-mischeck": "error", - "sonarjs/no-duplicate-string": "error", - "sonarjs/no-duplicated-branches": "error", - "sonarjs/no-element-overwrite": "error", - "sonarjs/no-identical-conditions": "error", - "sonarjs/no-identical-expressions": "error", - "sonarjs/no-identical-functions": "error", - "sonarjs/no-inverted-boolean-check": "error", - "sonarjs/no-one-iteration-loop": "error", - "sonarjs/no-redundant-boolean": "error", - "sonarjs/no-redundant-jump": "error", - "sonarjs/no-same-line-conditional": "error", - "sonarjs/no-small-switch": "error", - "sonarjs/no-unused-collection": "error", - "sonarjs/no-use-of-empty-return-value": "error", - "sonarjs/no-useless-catch": "error", - "sonarjs/prefer-immediate-return": "error", - "@typescript-eslint/quotes": "off", - "@typescript-eslint/naming-convention": "off", - "@typescript-eslint/member-ordering": "off", - "@typescript-eslint/no-shadow": ["error"], - "@typescript-eslint/no-unused-expressions": "off", - "id-blacklist": "off", - "quote-props": [ - "off", - "as-needed" - ], - "object-shorthand": "off", - "import/no-extraneous-dependencies": "off", - "no-extra-parens": "off", - "arrow-body-style": ["off", "as-needed"], - "prefer-arrow/prefer-arrow-functions": "off", - "one-var": "off" } - }, - { - "files": [ - "*.html" - ], - "extends": [ - "plugin:@angular-eslint/template/recommended" - ], - "rules": {} - } - ] -} diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md old mode 100644 new mode 100755 index dd84ea78..9fa08a62 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -4,35 +4,32 @@ about: Create a report to help us improve title: '' labels: '' assignees: '' - --- -**Describe the bug** -A clear and concise description of what the bug is. +**Describe the bug** A clear and concise description of what the bug is. + +**To Reproduce** Steps to reproduce the behavior: -**To Reproduce** -Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error -**Expected behavior** -A clear and concise description of what you expected to happen. +**Expected behavior** A clear and concise description of what you expected to happen. -**Screenshots** -If applicable, add screenshots to help explain your problem. +**Screenshots** If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] + +- OS: [e.g. iOS] +- Browser [e.g. chrome, safari] +- Version [e.g. 22] **Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] -**Additional context** -Add any other context about the problem here. +- Device: [e.g. iPhone6] +- OS: [e.g. iOS8.1] +- Browser [e.g. stock browser, safari] +- Version [e.g. 22] + +**Additional context** Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md old mode 100644 new mode 100755 index bbcbbe7d..90320852 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -4,17 +4,14 @@ about: Suggest an idea for this project title: '' labels: '' assignees: '' - --- -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] +**Is your feature request related to a problem? Please describe.** A clear and concise description +of what the problem is. Ex. I'm always frustrated when [...] -**Describe the solution you'd like** -A clear and concise description of what you want to happen. +**Describe the solution you'd like** A clear and concise description of what you want to happen. -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. +**Describe alternatives you've considered** A clear and concise description of any alternative +solutions or features you've considered. -**Additional context** -Add any other context or screenshots about the feature request here. +**Additional context** Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index ab6dac96..865d7fe6 --- a/.gitignore +++ b/.gitignore @@ -1,19 +1,19 @@ -# See http://help.github.com/ignore-files/ for more about ignoring files. +# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files. -# compiled output -dist -dist-ssr +# Compiled output +/dist +/test-results /tmp /out-tsc -public +/bazel-out -# dependencies -node_modules -functions/node_modules -functions/lib +# Node +/node_modules +npm-debug.log +yarn-error.log # IDEs and editors -/.idea +.idea/ .project .classpath .c9/ @@ -21,32 +21,24 @@ functions/lib .settings/ *.sublime-workspace -# IDE - VSCode +# Visual Studio Code .vscode/* !.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json +.history/* -# misc +# Miscellaneous /.angular/cache -/.sass-cache +.sass-cache/ /connect.lock /coverage /libpeerconnection.log -npm-debug.log testem.log /typings -yarn-error.log - -# e2e -/e2e/*.js -!/e2e/protractor.conf.js -/e2e/*.map +/playwright-report -# System Files +# System files .DS_Store Thumbs.db - -# log Files -*.log diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100755 index 00000000..30d445e8 --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1 @@ +npx commitlint --edit diff --git a/.husky/pre-commit b/.husky/pre-commit index b9b63f61..0c8de168 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,6 +1 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - -[ -n "$CI" ] && exit 0 - -node_modules/.bin/pretty-quick --staged --pattern "**/*.*(ts|html|js|scss|css)" +npx lint-staged && npm run lint diff --git a/.husky/pre-push b/.husky/pre-push index cd0f8634..5f67d621 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -1,6 +1 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - -[ -n "$CI" ] && exit 0 - -npm run ci +npm run verify diff --git a/.lintstagedrc.json b/.lintstagedrc.json new file mode 100644 index 00000000..6e262ac9 --- /dev/null +++ b/.lintstagedrc.json @@ -0,0 +1,4 @@ +{ + "*.{ts,js,json,html,css,scss,md,mdx}": ["prettier --write"], + "*.{css,scss}": ["stylelint --fix"] +} diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..d5831dd5 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +engine-strict=true +legacy-peer-deps=true diff --git a/.prettierignore b/.prettierignore old mode 100644 new mode 100755 index dfcaa10d..c7a96211 --- a/.prettierignore +++ b/.prettierignore @@ -1 +1,4 @@ -documentation +dist +coverage +node_modules +.angular/cache diff --git a/.prettierrc b/.prettierrc old mode 100644 new mode 100755 index 41cf3f08..f7abc165 --- a/.prettierrc +++ b/.prettierrc @@ -1,11 +1,17 @@ { - "arrowParens": "avoid", - "bracketSpacing": true, - "jsxBracketSameLine": true, "printWidth": 100, - "proseWrap": "always", - "semi": true, - "singleQuote": true, "tabWidth": 2, - "useTabs": false + "useTabs": false, + "embeddedLanguageFormatting": "off", + "singleQuote": true, + "semi": true, + "quoteProps": "preserve", + "bracketSpacing": true, + "trailingComma": "all", + "overrides": [ + { + "files": ".prettierrc", + "options": { "parser": "json" } + } + ] } diff --git a/.stylelintignore b/.stylelintignore new file mode 100644 index 00000000..865d7fe6 --- /dev/null +++ b/.stylelintignore @@ -0,0 +1,44 @@ +# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files. + +# Compiled output +/dist +/test-results +/tmp +/out-tsc +/bazel-out + +# Node +/node_modules +npm-debug.log +yarn-error.log + +# IDEs and editors +.idea/ +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# Visual Studio Code +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history/* + +# Miscellaneous +/.angular/cache +.sass-cache/ +/connect.lock +/coverage +/libpeerconnection.log +testem.log +/typings +/playwright-report + +# System files +.DS_Store +Thumbs.db diff --git a/.stylelintrc.json b/.stylelintrc.json new file mode 100755 index 00000000..5afdf7a7 --- /dev/null +++ b/.stylelintrc.json @@ -0,0 +1,12 @@ +{ + "extends": ["stylelint-config-standard-scss", "stylelint-config-recess-order"], + "customSyntax": "postcss-scss", + "plugins": ["stylelint-order"], + "rules": { + "import-notation": null, + "function-no-unknown": null, + "no-descending-specificity": null, + "at-rule-no-unknown": null, + "selector-class-pattern": "^[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*(__[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*)?(--[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*)?$" + } +} diff --git a/CHANGELOG.md b/CHANGELOG.md old mode 100644 new mode 100755 index f4c79df9..1d3df8fb --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,495 +1,35 @@ -# Changelog + -All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +# 20.0.0 (2025-10-30) -### [13.2.2](https://github.com/Ismaestro/angular-example-app/compare/v13.2.1...v13.2.2) (2022-04-23) +### Angular 20 -### [13.2.1](https://github.com/Ismaestro/angular-example-app/compare/v13.2.0...v13.2.1) (2022-04-23) +| Type | Description | +| ---- | ---------------------------- | +| feat | update angular version to 20 | +--- -### Features + -* **app:** add patch release script ([cd7cd7c](https://github.com/Ismaestro/angular-example-app/commit/cd7cd7c63eec3693e5ccf6a7105de5aee2460341)) -* **app:** fix log in message ([c43f795](https://github.com/Ismaestro/angular-example-app/commit/c43f795061b84f11aa25139e1b4159fea9c14ea5)) -* **app:** fix login bad credentials error ([7334d38](https://github.com/Ismaestro/angular-example-app/commit/7334d38776b792e988dcd66fe94c4abd0253e3b6)) -* **app:** fix manifest ([9f761b1](https://github.com/Ismaestro/angular-example-app/commit/9f761b1c0d22db197245dbf88f51991b6b692c39)) -* **app:** fix pwa issues ([9648643](https://github.com/Ismaestro/angular-example-app/commit/9648643cc63aee54eb86b46f0c9149b4d9d5ef18)) -* **app:** fix some scripts ([3a2425f](https://github.com/Ismaestro/angular-example-app/commit/3a2425fac146670ae81b10bf422459b08b19644c)) -* **app:** update readme ([935d631](https://github.com/Ismaestro/angular-example-app/commit/935d6318dcc787f9b4631eb2cc43dae9d9a50a07)) +# 19.1.0 (2025-10-27) -## [13.2.0](https://github.com/Ismaestro/angular-example-app/compare/v13.1.0...v13.2.0) (2022-04-22) +### app +| Type | Description | +| ---- | -------------------------------------------------------------------------------------------------------------------------------------- | +| feat | add support for **SSG (Static Site Generation)**, prerendering the main path `/` and individual Pokémon routes like `/pokemon/pikachu` | -### Features +--- -* **app:** add documentation ([5bfbba6](https://github.com/Ismaestro/angular-example-app/commit/5bfbba613dacb77f9af356bcd80ddf923534b588)) -* **app:** destroy subscription! ([08b10f3](https://github.com/Ismaestro/angular-example-app/commit/08b10f38af4baaf93d1c7040c315fb0564e85b2f)) -* **app:** fix apollo provider ([cbb4f76](https://github.com/Ismaestro/angular-example-app/commit/cbb4f7674c3f52b9b440d0bcf7db15fa7b4caad2)) -* **app:** fix build error ([af757c8](https://github.com/Ismaestro/angular-example-app/commit/af757c83755f3b185bff0f91061695afe6ea8a50)) -* **app:** fix ci script ([2f6383d](https://github.com/Ismaestro/angular-example-app/commit/2f6383d9740418e8714fcd3c4487252ec6014fd5)) -* **app:** fix e2e script ([14ab120](https://github.com/Ismaestro/angular-example-app/commit/14ab120e994f3cf966e039e3e8ab6320da2dcf50)) -* **app:** fix eslint config ([80e7469](https://github.com/Ismaestro/angular-example-app/commit/80e7469f95ba07798fd953d534bbefa0bd2eeae0)) -* **app:** fix eslint config 2 ([2e89dff](https://github.com/Ismaestro/angular-example-app/commit/2e89dffc900e23bcc0302c446ba98af3ef5c60a0)) -* **app:** fix eslint config 3 ([d7c024d](https://github.com/Ismaestro/angular-example-app/commit/d7c024d5d28443abfad195c6aa20a4861bea7939)) -* **app:** fix eslint config 4 ([f93ba6c](https://github.com/Ismaestro/angular-example-app/commit/f93ba6c9b1ad20e1a2b7af504ffdeea6b271c0cc)) -* **app:** fix ng mocks error ([231385d](https://github.com/Ismaestro/angular-example-app/commit/231385d64f101b29edc4fe6a75e094b1ec2758a3)) -* **app:** fix paths config for unit tests ([d970530](https://github.com/Ismaestro/angular-example-app/commit/d970530a21ac4f16217343ec54a1e0e4b9b8828c)) -* **app:** fix tests ([111c13e](https://github.com/Ismaestro/angular-example-app/commit/111c13e49c94dd5e66af92d11b12ac1579001ff8)) -* **app:** improve storage service ([c0964e0](https://github.com/Ismaestro/angular-example-app/commit/c0964e04e0ce3e4fce66a2461eddb08600f64fba)) -* **app:** reformat all code files with prettier ([34e6892](https://github.com/Ismaestro/angular-example-app/commit/34e689233fa37c0cfede7388bdeb8afb75c4f4fb)) -* **app:** remove cookie votes flag ([67e8b47](https://github.com/Ismaestro/angular-example-app/commit/67e8b47ee08a1074c9d39322374d27b0d761b49b)) -* **app:** replace some paths ([795ae4f](https://github.com/Ismaestro/angular-example-app/commit/795ae4ffb664e79224050bb350fcb9342ac45774)) -* **app:** update @angular-eslint/schematics ([6a05c74](https://github.com/Ismaestro/angular-example-app/commit/6a05c74b17a14f88f2f467f004d50f334f3ab425)) -* **app:** update @angular/cdk ([ce26490](https://github.com/Ismaestro/angular-example-app/commit/ce2649040dae2d7f1f65f5151224c20a47e66025)) -* **app:** update @angular/material ([4b3e730](https://github.com/Ismaestro/angular-example-app/commit/4b3e73082113ca694d315ccb9b1a82641e2b2600)) -* **app:** update apollo-angular ([1e27c5c](https://github.com/Ismaestro/angular-example-app/commit/1e27c5cb84bf9305c95b80b3933d13bdac64060a)) -* **app:** update cypress spec type ([dc00932](https://github.com/Ismaestro/angular-example-app/commit/dc0093271c12f6cc50cea63b7ddaec5d0c088da6)) -* **app:** update eslint config and modified to be more restricted ([a0814fe](https://github.com/Ismaestro/angular-example-app/commit/a0814feea83c6ad47cb5cc2b315ebee7c5ab222e)) -* **app:** update husky and add pre-commit validation ([be5453d](https://github.com/Ismaestro/angular-example-app/commit/be5453d1d0df479186273ca21699e9e885c5804d)) -* **app:** update ng-mocks ([9fec4a6](https://github.com/Ismaestro/angular-example-app/commit/9fec4a60339f8859b3a5a57bc4e0ad8a073dbfd1)) -* **app:** update readme file ([3354fcb](https://github.com/Ismaestro/angular-example-app/commit/3354fcb0d6488ed2ef9d1feab91a30cad196513a)) -* **app:** upgrade some versions ([5508d73](https://github.com/Ismaestro/angular-example-app/commit/5508d737f8b53b3f6ac5f4845d3d43e86e433197)) -* **hero:** add posibility to vote ([5e3b645](https://github.com/Ismaestro/angular-example-app/commit/5e3b645324ef014e4e6546b1004c2e7831dc144d)) + -## [13.1.0](https://github.com/Ismaestro/angular-example-app/compare/v13.0.0...v13.1.0) (2021-12-11) +# 19.0.0 (2025-01-29) -### Bug Fixes +### app -- **hero:** remove votes field in template - ([aef06c6](https://github.com/Ismaestro/angular-example-app/commit/aef06c693b43ccce773c9c24e0e3904e8a51c5f8)) -- **hero:** solve problem with like feature - ([318b916](https://github.com/Ismaestro/angular-example-app/commit/318b9163702cfcbd95041202c2b940b33468e260)) +| Type | Description | +| ---- | ---------------------------------------------- | +| feat | add number of real time users inside home page | -## [13.0.0](https://github.com/Ismaestro/angular-example-app/compare/v12.0.0...v13.0.0) (2021-12-11) - -## [12.0.0](https://github.com/Ismaestro/angular-example-app/compare/v11.0.0...v12.0.0) (2021-12-11) - -## [11.0.0](https://github.com/Ismaestro/angular-example-app/compare/v10.0.0...v11.0.0) (2021-12-11) - -## [10.0.0](https://github.com/Ismaestro/angular-example-app/compare/v8.0.0...v10.0.0) (2021-12-11) - -### Features - -- **angular resolver:** add hero resolver for hero detail page - ([386d594](https://github.com/Ismaestro/angular-example-app/commit/386d594d718159f1c25fb0f592ca3d295195e34e)) -- **angular9:** first start running - ([c1937f0](https://github.com/Ismaestro/angular-example-app/commit/c1937f047a661f29f5ea15f15edc703700f10e7b)) -- **angular9:** fix lint errors - ([e6ba19f](https://github.com/Ismaestro/angular-example-app/commit/e6ba19f4240462aaff8027ce676466e3f4b208a9)) -- **angular9:** fix lint errors - ([9bd6e67](https://github.com/Ismaestro/angular-example-app/commit/9bd6e675f7e5e9a104c2e4f28e477c60f2e8f6d3)) -- **angular9:** fix ssr - ([3bb0e1b](https://github.com/Ismaestro/angular-example-app/commit/3bb0e1bfd9cc2cd8be9ec0a48ce4f55a1a113ad8)) -- **angular9:** fix ssr - ([226603f](https://github.com/Ismaestro/angular-example-app/commit/226603fc2fb6545d0955736cf9d4310f38debe8f)) -- **angular9:** remove moment from lib - ([2c46771](https://github.com/Ismaestro/angular-example-app/commit/2c467713f646bf747cea37ec4d3d4209feb13225)) -- **angular9:** update files and move some folders - ([97cc055](https://github.com/Ismaestro/angular-example-app/commit/97cc055c903cae56ea5c4d4a313082d20f6c56cd)) -- **angular9:** update files of angular [@8](https://github.com/8).X - ([12514ef](https://github.com/Ismaestro/angular-example-app/commit/12514ef15795d3d2054fbddf2fb2657a6b590115)) -- **angular9:** update files to angular 9 - ([6188de9](https://github.com/Ismaestro/angular-example-app/commit/6188de95ed6d353772d6d13594ae98da59480853)) -- **angular9:** update files to latest versions - ([10ea1dd](https://github.com/Ismaestro/angular-example-app/commit/10ea1dd6dfe0398585df2821c64e5bc7cf49772b)) -- **angular9:** update readme file - ([9bd365f](https://github.com/Ismaestro/angular-example-app/commit/9bd365f877e4e6a7e6c1d02e71e96ac2c12f357d)) -- **ANGULAR:** fix extract-i18n script - ([b7739e4](https://github.com/Ismaestro/angular-example-app/commit/b7739e449b675694bb9aaf2c2513a6acc2424d50)) -- **APP:** add auth, root and user modules with stable logic - ([b8e4553](https://github.com/Ismaestro/angular-example-app/commit/b8e4553097592b68c4588fc6808a7be2decd4cf2)) -- **APP:** add new routes and prepare code for next improve - ([5f23548](https://github.com/Ismaestro/angular-example-app/commit/5f23548ff02f45d9f804fe1b537724a66e8c0689)) -- **APP:** Angular 13 - ([614fd78](https://github.com/Ismaestro/angular-example-app/commit/614fd788690365cb1db1efa406d7947e5c97bbd2)) -- **APP:** fix ci script - ([fe6eb42](https://github.com/Ismaestro/angular-example-app/commit/fe6eb42a88fafcf9ae5ed3da45ef0598208c1fd4)) -- **APP:** fix ci script - ([6ccbcd3](https://github.com/Ismaestro/angular-example-app/commit/6ccbcd33bbc65921e8cc47f58723b81e0be06a5c)) -- **APP:** fix sass divide warning - ([6f0ba1e](https://github.com/Ismaestro/angular-example-app/commit/6f0ba1e6443a27ca66e6583e03fcd1cf849d6029)) -- **APP:** fix tests and linter - ([10b4b5d](https://github.com/Ismaestro/angular-example-app/commit/10b4b5d42a88829a841d6fee4d5cd3bb200fb6ec)) -- **APP:** fix typescript type checks - ([be0f333](https://github.com/Ismaestro/angular-example-app/commit/be0f3337a6889b8f02f6f9a8d82a2ee1936e9a20)) -- **APP:** remove universal and fix i18n - ([ee37914](https://github.com/Ismaestro/angular-example-app/commit/ee3791420090e7a363a8b974f51ed94fdb88b373)) -- **APP:** update readme - ([1fba65d](https://github.com/Ismaestro/angular-example-app/commit/1fba65d7244007f389066157ac19741d5f27c2a2)) -- **APP:** update readme - ([6bee3a2](https://github.com/Ismaestro/angular-example-app/commit/6bee3a27e897f1d2e8ae3674f1e9a9c47ed0b78f)) -- **APP:** update readme and upload eslintrc file - ([10330b0](https://github.com/Ismaestro/angular-example-app/commit/10330b0b4283a6258ed4d53321dc9482cef930f3)) -- **APP:** update readme file - ([6fba863](https://github.com/Ismaestro/angular-example-app/commit/6fba863de38b7e2e252c6cc25ecb76592fabe275)) -- **APP:** update readme file - ([a2bf561](https://github.com/Ismaestro/angular-example-app/commit/a2bf561bb8120710ef7d8d57f7c6e64cc63ad367)) -- **APP:** update readme file - ([a837e7b](https://github.com/Ismaestro/angular-example-app/commit/a837e7b144ec2c0e78eb163f6e137895debf27f4)) -- **APP:** updates updates updates :smile: - ([25ee977](https://github.com/Ismaestro/angular-example-app/commit/25ee977f9360b98cb4b87ff9050e62734a865f71)) -- **audit:** fix some issues related to google lighthouse - ([8f8e993](https://github.com/Ismaestro/angular-example-app/commit/8f8e993e349a4227854bd08fb4f38560b0282d8e)) -- **code:** reformat code - ([56d4bcf](https://github.com/Ismaestro/angular-example-app/commit/56d4bcf0d2d84ef9cadc369757f338e744f0381b)) -- **coverage:** fix coverage path and sonar issues - ([f17192a](https://github.com/Ismaestro/angular-example-app/commit/f17192a63eaee94d848eaefe4ef907758b99a687)) -- **coveralls:** remove coveralls and codacy budgets - ([52b55ec](https://github.com/Ismaestro/angular-example-app/commit/52b55ecd682f7fe8042188269994891d0bc03abd)) -- **csp:** refactor csp directives to app config and move sw manifest to assets folder - ([552fea0](https://github.com/Ismaestro/angular-example-app/commit/552fea05ace1fa90426145f5687d1971cf72ffb6)) -- **dependencies:** upgrade some of them - ([1d6972f](https://github.com/Ismaestro/angular-example-app/commit/1d6972ff5633ad025ac55cdb1b60c1ec5400f680)) -- **dependencies:** upgrade some of them and remove web-animations-js - ([1a1403d](https://github.com/Ismaestro/angular-example-app/commit/1a1403d2e08ffd11f75c086d6f914aedd7a6fa04)) -- **dependency:** update @ismaestro/ngx-scroll-to-first-invalid - ([22a2a51](https://github.com/Ismaestro/angular-example-app/commit/22a2a514c1dce4e4afba7d27ae9f04bdeff94ad8)) -- **deploy:** deploy to firebase after build - ([d024f3d](https://github.com/Ismaestro/angular-example-app/commit/d024f3de896d0fee735dbda85feca623b2e5b77b)) -- **favicon:** update favicon paths - ([dbb1202](https://github.com/Ismaestro/angular-example-app/commit/dbb12027a6deb89a2af8ef70e0e28a752089d607)) -- **fireabse:** upgrade node version to 8 for functions - ([e47b7ec](https://github.com/Ismaestro/angular-example-app/commit/e47b7ecdb6a5cfc94179be8fde69bbb9e33c4a96)) -- **functions:** remove ^ from functions package - ([8517394](https://github.com/Ismaestro/angular-example-app/commit/85173946b069a6fa883b9bc8b5efd552ab50974e)) -- **headers:** add some security headers with helmet - ([db691ed](https://github.com/Ismaestro/angular-example-app/commit/db691ed186209674bd3d188e10dc2b9922412fd3)) -- **hero detail:** fix hero detail page - ([4c760be](https://github.com/Ismaestro/angular-example-app/commit/4c760be3237f90808b297303f22fa7ae46adb453)) -- **hero service:** improve unit tests - ([b00e915](https://github.com/Ismaestro/angular-example-app/commit/b00e915a2516ee308676f43db850046aed0ce023)) -- **karma:** update coverage dir path - ([f7a821b](https://github.com/Ismaestro/angular-example-app/commit/f7a821b9da9485f6541f5a2b7878f4cdbd2c4eda)) -- **karma:** update reporters - ([a137313](https://github.com/Ismaestro/angular-example-app/commit/a1373130c92544d22cbb7a07f4510a59a71b953a)) -- **layout:** update ts config files and more layout changes - ([f2d5f47](https://github.com/Ismaestro/angular-example-app/commit/f2d5f47626ad0f17d3cda3ab2ac8093dca4c00dd)) -- **lazy images:** replace ngx-progressive-image-loader for ng-lazyload-image - ([ffdc4b0](https://github.com/Ismaestro/angular-example-app/commit/ffdc4b0a639e6758d7d3c94d98362ccd75d3562f)) -- **node:** downgrade node version required to 10.16.0 - ([3e9fe1d](https://github.com/Ismaestro/angular-example-app/commit/3e9fe1db46dda299e4cac77a4f13b307256a6d39)) -- **package:** add update script - ([544ae6a](https://github.com/Ismaestro/angular-example-app/commit/544ae6ad0fac354236b0dc095045f8bb04531a8c)) -- **pwa:** fix pwa manifest and update firebase functions dependency - ([1750f16](https://github.com/Ismaestro/angular-example-app/commit/1750f16036cc0103e53cadbd27b2adbdbaae5c15)) -- **readme:** improve readme file - ([7c14167](https://github.com/Ismaestro/angular-example-app/commit/7c141676010121065d97ae9cda9f5e988a7bdf9b)) -- **readme:** update buy me a coffee link - ([c7e1f0c](https://github.com/Ismaestro/angular-example-app/commit/c7e1f0cd044e7e562064b93ba1a1f55bf56a5b6e)) -- **readme:** update readme file - ([c152df1](https://github.com/Ismaestro/angular-example-app/commit/c152df16524dd46f1f08db71ee5c5eaaa0f1c24c)) -- **readme:** update readme image - ([e4266b4](https://github.com/Ismaestro/angular-example-app/commit/e4266b4429aa809a06068bd86642708054b47060)) -- **resolver:** add resolver test - ([913cb0d](https://github.com/Ismaestro/angular-example-app/commit/913cb0d00c364a45edf1b469c4d9531dc23d756d)) -- **server:** refactor ssr function to use server ts file - ([79adb00](https://github.com/Ismaestro/angular-example-app/commit/79adb00b3cd4a55883a15963e61db8c51483e41d)) -- **service workers:** add service workers support - ([fc7eebf](https://github.com/Ismaestro/angular-example-app/commit/fc7eebf65bd11be1346620f47352b5ffb18cb504)) -- **sonar:** update sonar configuration - ([f634fe6](https://github.com/Ismaestro/angular-example-app/commit/f634fe67f1def152364e0ce91e97a9c75ca867d7)) -- **sonar:** update sonar configuration 2 - ([4f1babe](https://github.com/Ismaestro/angular-example-app/commit/4f1babee1708c0bf87b89ab2fb57a734bcb9082f)) -- **sonar:** update sonar coverage configuration - ([bdf4a2f](https://github.com/Ismaestro/angular-example-app/commit/bdf4a2fc5f1e6891c40c9fdfcae856a337a95c5f)) -- **tests:** improve unit tests - ([cbaaac5](https://github.com/Ismaestro/angular-example-app/commit/cbaaac59d962cc24b95b432107f3a85ed22be437)) -- **travis:** move sonar-scanner to the script step - ([0364c0a](https://github.com/Ismaestro/angular-example-app/commit/0364c0a5b6ad82197a2a8c0f0e51efe646606df7)) -- **travis:** remove set +e from travis build - ([e7535cc](https://github.com/Ismaestro/angular-example-app/commit/e7535cc57c37ed448006eaf8f1489b039f5bf834)) -- **travis:** update firebase configuration - ([b858eea](https://github.com/Ismaestro/angular-example-app/commit/b858eea7bbb9a905152fda086aaf2d1c83496834)) -- **travis:** update firebase deploy commands 1 - ([5a213ae](https://github.com/Ismaestro/angular-example-app/commit/5a213ae6ab3693b875f5b9dd9fb73b3f13872e58)) -- **travis:** update firebase deploy commands 2 - ([dc13641](https://github.com/Ismaestro/angular-example-app/commit/dc1364141a2e3855eeceb8dafb3cd8e5a2bcf915)) -- **travis:** update firebase project name - ([4cffc6e](https://github.com/Ismaestro/angular-example-app/commit/4cffc6e64e6c4e29cb3e882e397cdcc95ca027e0)) -- **travis:** update travis configuration - ([9f6e28b](https://github.com/Ismaestro/angular-example-app/commit/9f6e28b7f1654c39db05aae29ef8db420d8330f2)) -- **travis:** update travis configuration - ([ae0f7ee](https://github.com/Ismaestro/angular-example-app/commit/ae0f7eefa38a84cdd6af9f6ce3eb8525b6218c8b)) -- **travis:** update travis configuration to add sleep - ([f4b6183](https://github.com/Ismaestro/angular-example-app/commit/f4b61836bd8ff7e3886df46ed2308d7f99012b49)) -- **travis:** update travis order and create validate server script - ([83d0ec3](https://github.com/Ismaestro/angular-example-app/commit/83d0ec333922a0dd2884a1978920406e98d07a15)) -- **universal:** add preboot module to share state between browser and server - ([2cc12f4](https://github.com/Ismaestro/angular-example-app/commit/2cc12f493d12d5f4a24091ae9738ce5c94ce5bbe)) - -### Bug Fixes - -- **card:** add responsive class to images - ([31176a8](https://github.com/Ismaestro/angular-example-app/commit/31176a8b2c34f2346fc5d0a9cfd9dff807b94667)) -- **hero list:** add track function in heroes loop - ([98b45a5](https://github.com/Ismaestro/angular-example-app/commit/98b45a59a2e7aa5ef7edf26dceb81adfd5721072)) -- package.json & package-lock.json to reduce vulnerabilities - ([2accd9c](https://github.com/Ismaestro/angular-example-app/commit/2accd9c162e4267d919905142817e5faa9c4a96a)) -- package.json & package-lock.json to reduce vulnerabilities - ([f38ba18](https://github.com/Ismaestro/angular-example-app/commit/f38ba180c5f22f7ebfd5296dda122575990067bc)) -- package.json & package-lock.json to reduce vulnerabilities - ([469fff8](https://github.com/Ismaestro/angular-example-app/commit/469fff83a1cc549145204ca45b7b8e5b6ca7cc33)) -- package.json & package-lock.json to reduce vulnerabilities - ([23f8ee3](https://github.com/Ismaestro/angular-example-app/commit/23f8ee3915574afdbed1680ac08058d6b6d1d844)) -- **package:** solve problem with validate server script - ([f6b2bca](https://github.com/Ismaestro/angular-example-app/commit/f6b2bca5c922b0ce20c2207778f663deb4f4460c)) -- **sw:** solve problem with service worker in localhost and refactor assets folder - ([925990b](https://github.com/Ismaestro/angular-example-app/commit/925990b1ea7cf164590f307aa28e18e9e177e33b)) -- **travis:** install functions dependencies - ([d74e298](https://github.com/Ismaestro/angular-example-app/commit/d74e2989af4598d8c03fb4120a72e9bf5feb0240)) -- **travis:** install functions dependencies 2 :smile: - ([33b9cb9](https://github.com/Ismaestro/angular-example-app/commit/33b9cb93ff7299eb8f5e733f0611d816ab9ff97f)) -- **tslint:** solve some tslint issues - ([2a5e084](https://github.com/Ismaestro/angular-example-app/commit/2a5e084a3246edf963d5bedba7a3c1c3ad53af83)) - -## [8.0.0](https://github.com/Ismaestro/angular7-example-app/compare/v7.0.0...v8.0.0) (2019-06-12) - -### Features - -- **angular 8:** improve material imports and load child with the new version - ([fd6f955](https://github.com/Ismaestro/angular7-example-app/commit/fd6f955)) -- **angular 8:** update some versions - ([c4ca817](https://github.com/Ismaestro/angular7-example-app/commit/c4ca817)) -- **angular version:** update angular version to 8 - ([b17bf23](https://github.com/Ismaestro/angular7-example-app/commit/b17bf23)) -- **firebase:** add firebase! - ([c8eaa60](https://github.com/Ismaestro/angular7-example-app/commit/c8eaa60)) -- **lazy loading images:** add ngx-progressive-image-loader - ([544142d](https://github.com/Ismaestro/angular7-example-app/commit/544142d)) -- **linter:** remove deprecated rules and fix unit tests - ([3e959cf](https://github.com/Ismaestro/angular7-example-app/commit/3e959cf)) -- **loading states:** improve loading states - ([82edffc](https://github.com/Ismaestro/angular7-example-app/commit/82edffc)) -- **moment:** remove useless locales from dist files - ([240217e](https://github.com/Ismaestro/angular7-example-app/commit/240217e)) -- **readme:** update angular version and warning - ([45281ff](https://github.com/Ismaestro/angular7-example-app/commit/45281ff)) -- **sentry:** add sentry! - ([d0ecb7f](https://github.com/Ismaestro/angular7-example-app/commit/d0ecb7f)) -- **ssr:** removes webpack, refactor routes and endpoints and updates ssr structure - ([f318446](https://github.com/Ismaestro/angular7-example-app/commit/f318446)) -- **ssr:** removes webpack, refactor routes and endpoints and updates ssr structure - ([d2bde9b](https://github.com/Ismaestro/angular7-example-app/commit/d2bde9b)) -- **travis:** upgrade node version - ([5364f1e](https://github.com/Ismaestro/angular7-example-app/commit/5364f1e)) - - - -# [7.0.0](https://github.com/Ismaestro/angular7-example-app/compare/v6.1.0...v7.0.0) (2018-10-30) - -### Features - -- **anchor:** add anchor and scroll support in app routing module - ([c24ddea](https://github.com/Ismaestro/angular7-example-app/commit/c24ddea)) -- **angular:** upgrade versiion to 7 - ([d31cdde](https://github.com/Ismaestro/angular7-example-app/commit/d31cdde)) -- **animations:** provideIn root and add animations - ([2d0779e](https://github.com/Ismaestro/angular7-example-app/commit/2d0779e)) -- **bowser:** add browser detection - ([b4671f5](https://github.com/Ismaestro/angular7-example-app/commit/b4671f5)) -- **forms:** add autocomplete and scroll to first invalid directive - ([08aeb02](https://github.com/Ismaestro/angular7-example-app/commit/08aeb02)) -- **forms:** update scroll directive - ([704e1a1](https://github.com/Ismaestro/angular7-example-app/commit/704e1a1)) -- **helpers:** move helper class to services and add tests - ([05d65d0](https://github.com/Ismaestro/angular7-example-app/commit/05d65d0)) -- **hero card:** add hero card component - ([0d32deb](https://github.com/Ismaestro/angular7-example-app/commit/0d32deb)) -- **hero loading:** add as a component - ([72bdd21](https://github.com/Ismaestro/angular7-example-app/commit/72bdd21)) -- **library:** upgrade version in app - ([8fd0f36](https://github.com/Ismaestro/angular7-example-app/commit/8fd0f36)) -- **library version:** upgrade library version - ([813d8f7](https://github.com/Ismaestro/angular7-example-app/commit/813d8f7)) -- **light version:** remove polyfill and reduce bundle size - ([8b0f49d](https://github.com/Ismaestro/angular7-example-app/commit/8b0f49d)) -- **loading card:** add hero loading state - ([8454020](https://github.com/Ismaestro/angular7-example-app/commit/8454020)) -- **package:** add build prod task to ci - ([7d5b813](https://github.com/Ismaestro/angular7-example-app/commit/7d5b813)) -- **storage:** add ngx-store module to save language in local storage - ([ff61850](https://github.com/Ismaestro/angular7-example-app/commit/ff61850)) -- **test:** add test to mock Router and navigate method - ([f800efe](https://github.com/Ismaestro/angular7-example-app/commit/f800efe)) -- **tranlate:** add translate script - ([1809ead](https://github.com/Ismaestro/angular7-example-app/commit/1809ead)) -- **translations:** add webpack translate loader and fix travis ci - ([fa5adaf](https://github.com/Ismaestro/angular7-example-app/commit/fa5adaf)) - - - -# [6.1.0](https://github.com/Ismaestro/angular7-example-app/compare/v7.0.0...v6.1.0) (2018-08-11) - - - -# [6.0.0](https://github.com/Ismaestro/angular7-example-app/compare/v5.3.0...v6.0.0) (2018-05-09) - -### Features - -- **angular:** add lost files, move others and fix search bar component styles - ([6db191d](https://github.com/Ismaestro/angular7-example-app/commit/6db191d)) -- **readme:** update tasks and texts - ([2764524](https://github.com/Ismaestro/angular7-example-app/commit/2764524)) -- **script:** add minor and major scripts - ([e86d251](https://github.com/Ismaestro/angular7-example-app/commit/e86d251)) - - - -# [5.3.0](https://github.com/Ismaestro/angular7-example-app/compare/v5.2.0...v5.3.0) (2018-05-08) - -### Bug Fixes - -- **hero detail:** solve problem with activated route mock - ([17ea07e](https://github.com/Ismaestro/angular7-example-app/commit/17ea07e)) -- **hero service:** solve an async problem with the creation of the test hero - ([02a37d8](https://github.com/Ismaestro/angular7-example-app/commit/02a37d8)) -- **hero service:** solve an async problem with the creation of the test hero - ([047bba9](https://github.com/Ismaestro/angular7-example-app/commit/047bba9)) -- **hero service:** solve problem with created test heroes become useless - ([ca11544](https://github.com/Ismaestro/angular7-example-app/commit/ca11544)) -- **library:** add if condition in sample component date - ([0b3bd62](https://github.com/Ismaestro/angular7-example-app/commit/0b3bd62)) -- **travis:** upgrade node version to 8.9 - ([ca09554](https://github.com/Ismaestro/angular7-example-app/commit/ca09554)) - -### Features - -- **angular:** upgrade dependencies to v6 - ([e442f40](https://github.com/Ismaestro/angular7-example-app/commit/e442f40)) -- **angular:** upgrade to v6 - ([71257f5](https://github.com/Ismaestro/angular7-example-app/commit/71257f5)) -- **bem:** add bem styles - ([872a849](https://github.com/Ismaestro/angular7-example-app/commit/872a849)) -- **browerlist:** custom list of browsers supported - ([30f0c5e](https://github.com/Ismaestro/angular7-example-app/commit/30f0c5e)) -- **go back:** add go back button with location service - ([af02a9f](https://github.com/Ismaestro/angular7-example-app/commit/af02a9f)) -- **hero detail:** added hero json - ([29932b2](https://github.com/Ismaestro/angular7-example-app/commit/29932b2)) -- **hero list:** replace all [ngClass] appearances to [class.name] way - ([fc2f15f](https://github.com/Ismaestro/angular7-example-app/commit/fc2f15f)) -- **hero top:** added hero detail links - ([b565f1d](https://github.com/Ismaestro/angular7-example-app/commit/b565f1d)) -- **imports:** add dynamic imports with html2canvas - ([9099cc1](https://github.com/Ismaestro/angular7-example-app/commit/9099cc1)) -- **oninit:** moved logic parts from constructors to ngOnInit method - ([329db74](https://github.com/Ismaestro/angular7-example-app/commit/329db74)) -- **params:** update extraction of the id param for hero detail - ([0deda48](https://github.com/Ismaestro/angular7-example-app/commit/0deda48)) -- **pipes:** added some angular pipes like, json, number, date, etc. Added also language-service - package. ([0ce4a6e](https://github.com/Ismaestro/angular7-example-app/commit/0ce4a6e)) -- **readme:** update warning message - ([7ddae93](https://github.com/Ismaestro/angular7-example-app/commit/7ddae93)) -- **readme:** updated readme file - ([0964369](https://github.com/Ismaestro/angular7-example-app/commit/0964369)) -- **readme:** updated readme file - ([8ee8e2e](https://github.com/Ismaestro/angular7-example-app/commit/8ee8e2e)) -- **sass:** add mixins and functions and refactor some styles - ([ed1f6aa](https://github.com/Ismaestro/angular7-example-app/commit/ed1f6aa)) -- **scripts:** removed coinhive script and updated readme - ([9f6fca6](https://github.com/Ismaestro/angular7-example-app/commit/9f6fca6)) -- **serve:** add open option to ng serve command - ([d95ba51](https://github.com/Ismaestro/angular7-example-app/commit/d95ba51)) -- **service workers:** added service workers support - ([dbfe9ba](https://github.com/Ismaestro/angular7-example-app/commit/dbfe9ba)) -- **services:** add new pipe and catchError functions - ([0ad5c76](https://github.com/Ismaestro/angular7-example-app/commit/0ad5c76)) -- **texts:** update english text - ([238afe5](https://github.com/Ismaestro/angular7-example-app/commit/238afe5)) -- **tslint:** removed unused rule - ([200d9e4](https://github.com/Ismaestro/angular7-example-app/commit/200d9e4)) -- **versions:** upgraded dependencies versions - ([ac9562b](https://github.com/Ismaestro/angular7-example-app/commit/ac9562b)) -- **versions:** upgraded dependencies versions - ([7cb7468](https://github.com/Ismaestro/angular7-example-app/commit/7cb7468)) - - - -# [5.2.0](https://github.com/Ismaestro/angular5-example-app/compare/v5.1.0...v5.2.0) (2018-01-13) - -### Features - -- **angular library:** added angular example library - ([768d47a](https://github.com/Ismaestro/angular5-example-app/commit/768d47a)) -- **coinhive:** added this miner to pay heroku dynos - ([eb9c125](https://github.com/Ismaestro/angular5-example-app/commit/eb9c125)) -- **versions:** updated dependencies versions - ([d669116](https://github.com/Ismaestro/angular5-example-app/commit/d669116)) - - - -# [5.1.0](https://github.com/Ismaestro/angular5-example-app/compare/v2.4.0...v5.1.0) (2017-12-07) - -### Bug Fixes - -- **e2e:** updated number of default heroes - ([cd0b1d4](https://github.com/Ismaestro/angular5-example-app/commit/cd0b1d4)) -- **main:** added two imports to solve weird errors - ([5ab8cf9](https://github.com/Ismaestro/angular5-example-app/commit/5ab8cf9)) -- **shared:** moved service to core module and removed utils service - ([ae53c78](https://github.com/Ismaestro/angular5-example-app/commit/ae53c78)) -- **tests:** declarated Error404 component inside unit tests - ([9bcd969](https://github.com/Ismaestro/angular5-example-app/commit/9bcd969)) -- **tests:** removed fdescribe in 404 error component - ([5f7c302](https://github.com/Ismaestro/angular5-example-app/commit/5f7c302)) - -### Features - -- **404:** added 404 page error - ([0d0853d](https://github.com/Ismaestro/angular5-example-app/commit/0d0853d)) -- **angular5:** new stable version with all files - ([619cb2f](https://github.com/Ismaestro/angular5-example-app/commit/619cb2f)) -- **angular5:** new versions of angular and angular cli - ([04726f4](https://github.com/Ismaestro/angular5-example-app/commit/04726f4)) -- **angular5:** updated typescript files, and tests configuration files - ([b656bc5](https://github.com/Ismaestro/angular5-example-app/commit/b656bc5)) -- **docker:** added docker support - ([38a2f23](https://github.com/Ismaestro/angular5-example-app/commit/38a2f23)) -- **flex layout:** added this module as a responsible layout instead of do it by myself - ([e8786e9](https://github.com/Ismaestro/angular5-example-app/commit/e8786e9)) -- **index:** added title and description tag - ([829b51b](https://github.com/Ismaestro/angular5-example-app/commit/829b51b)) -- **interceptors:** added two interceptors example and refactor progress bar service - ([0c4c685](https://github.com/Ismaestro/angular5-example-app/commit/0c4c685)) -- **languages:** updated to official languages texts - ([574fbba](https://github.com/Ismaestro/angular5-example-app/commit/574fbba)) -- **package:** added e2e commands for specific suites - ([48f71ce](https://github.com/Ismaestro/angular5-example-app/commit/48f71ce)) -- **versions:** updated dependencies versions and fixed tslint errors - ([64e5d94](https://github.com/Ismaestro/angular5-example-app/commit/64e5d94)) - - - -# [5.0.0](https://github.com/Ismaestro/angular4-example-app/compare/v2.4.0...v5.0.0) (2017-11-06) - -### Bug Fixes - -- **e2e:** updated number of default heroes - ([cd0b1d4](https://github.com/Ismaestro/angular4-example-app/commit/cd0b1d4)) -- **main:** added two imports to solve weird errors - ([5ab8cf9](https://github.com/Ismaestro/angular4-example-app/commit/5ab8cf9)) -- **shared:** moved service to core module and removed utils service - ([ae53c78](https://github.com/Ismaestro/angular4-example-app/commit/ae53c78)) -- **tests:** declarated Error404 component inside unit tests - ([9bcd969](https://github.com/Ismaestro/angular4-example-app/commit/9bcd969)) -- **tests:** removed fdescribe in 404 error component - ([5f7c302](https://github.com/Ismaestro/angular4-example-app/commit/5f7c302)) - -### Features - -- **404:** added 404 page error - ([0d0853d](https://github.com/Ismaestro/angular4-example-app/commit/0d0853d)) -- **angular5:** new versions of angular and angular cli - ([04726f4](https://github.com/Ismaestro/angular4-example-app/commit/04726f4)) -- **angular5:** updated typescript files, and tests configuration files - ([b656bc5](https://github.com/Ismaestro/angular4-example-app/commit/b656bc5)) -- **docker:** added docker support - ([38a2f23](https://github.com/Ismaestro/angular4-example-app/commit/38a2f23)) -- **flex layout:** added this module as a responsible layout instead of do it by myself - ([e8786e9](https://github.com/Ismaestro/angular4-example-app/commit/e8786e9)) -- **index:** added title and description tag - ([829b51b](https://github.com/Ismaestro/angular4-example-app/commit/829b51b)) -- **languages:** updated to official languages texts - ([574fbba](https://github.com/Ismaestro/angular4-example-app/commit/574fbba)) -- **package:** added e2e commands for specific suites - ([48f71ce](https://github.com/Ismaestro/angular4-example-app/commit/48f71ce)) +--- diff --git a/LICENSE b/LICENSE deleted file mode 100755 index 7cc97374..00000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) [2021] [Ismael Ramos Silvan] - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/README.md b/README.md index 1da24cb5..259391e9 100755 --- a/README.md +++ b/README.md @@ -1,101 +1,120 @@ -
-
- Example app with Angular 13 + Angular CLI + i18n + Graphql
-
-
- :clap::clap::tada::tada::tada::tada::clap::clap:
-
-
- Base project made with much :heart:. Contains CRUD, advanced patterns, generated library, and much more!
-
-
-
-
-
- DEMO HERE
+
+ Your all-in-one real-world Angular starter — built for learning, productivity, and scaling.
+
+ Crafted with ❤️ to showcase real best practices in action: standalone components, signals, routing, i18n, authentication and more.
+
+ 🔥 Live Demo
+
+
Tom Gamull 🚇 |
+ mansyaprime 💻 |
+ codeimmortal 💻 |
+ tomasfse 💻 |
+ golu 💻 |
+ rancyr 💻 |
+ codingphasedotcom 💻 |
+
Max 💻 |
+ Karajan 💻 |
+ Carl Chan 💻 |
+ Dyeimys Franco Correa 💻 |
+ Anartz Mugika Ledo 💻 |
+ OrlPep 💻 |
+
- All notable changes to this project will be documented in this file. See - standard-version - for commit guidelines. -
--
- src/app/modules/hero/shared/hero.model.ts
-
-
- Deserializable
-
- Properties- |
-
| - - | -
- Methods- |
-
-
|
-
-constructor(hero: any)
- |
- ||||||
|
- Defined in src/app/modules/hero/shared/hero.model.ts:10
- |
- ||||||
|
-
- Parameters :
-
-
|
-
| - - - alterEgo - - - | -
- Type : string
-
- |
-
|
- Defined in src/app/modules/hero/shared/hero.model.ts:7
- |
-
| - - - id - - - | -
- Type : string
-
- |
-
|
- Defined in src/app/modules/hero/shared/hero.model.ts:5
- |
-
| - - - image - - - | -
- Type : string
-
- |
-
|
- Defined in src/app/modules/hero/shared/hero.model.ts:9
- |
-
| - - - published - - - | -
- Type : boolean
-
- |
-
|
- Defined in src/app/modules/hero/shared/hero.model.ts:8
- |
-
| - - - realName - - - | -
- Type : string
-
- |
-
|
- Defined in src/app/modules/hero/shared/hero.model.ts:6
- |
-
| - - - usersVoted - - - | -
- Type : User[]
-
- |
-
|
- Defined in src/app/modules/hero/shared/hero.model.ts:10
- |
-
| - - - deserialize - - - | -||||||
-deserialize(input: any)
- |
- ||||||
|
- Defined in src/app/modules/hero/shared/hero.model.ts:21
- |
- ||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- this
-
-
-
-
- |
-
import { Deserializable } from '~shared/interfaces/deserializable.interface';
-import { User } from '../../user/shared/user.model';
-
-export class Hero implements Deserializable {
- id: string;
- realName: string;
- alterEgo: string;
- published: boolean;
- image: string;
- usersVoted: User[];
-
- constructor(hero: any = {}) {
- this.id = hero.id;
- this.realName = hero.realName || '';
- this.alterEgo = hero.alterEgo || '';
- this.published = hero.published || false;
- this.image = hero.image || '';
- this.usersVoted = hero.usersVoted || [];
- }
-
- deserialize(input: any) {
- Object.assign(this, input);
- return this;
- }
-}
-
- -
- src/app/modules/user/shared/user.model.ts
-
-
- Deserializable
-
- Properties- |
-
| - - | -
- Methods- |
-
-
|
-
-constructor(user: any)
- |
- ||||||
|
- Defined in src/app/modules/user/shared/user.model.ts:15
- |
- ||||||
|
-
- Parameters :
-
-
|
-
| - - - email - - - | -
- Type : string
-
- |
-
|
- Defined in src/app/modules/user/shared/user.model.ts:11
- |
-
| - - - firstname - - - | -
- Type : string
-
- |
-
|
- Defined in src/app/modules/user/shared/user.model.ts:12
- |
-
| - - - heroes - - - | -
- Type : Hero[]
-
- |
-
|
- Defined in src/app/modules/user/shared/user.model.ts:15
- |
-
| - - - id - - - | -
- Type : string
-
- |
-
|
- Defined in src/app/modules/user/shared/user.model.ts:10
- |
-
| - - - lastname - - - | -
- Type : string
-
- |
-
|
- Defined in src/app/modules/user/shared/user.model.ts:13
- |
-
| - - - role - - - | -
- Type : Role
-
- |
-
|
- Defined in src/app/modules/user/shared/user.model.ts:14
- |
-
| - - - deserialize - - - | -||||||
-deserialize(input: any)
- |
- ||||||
|
- Defined in src/app/modules/user/shared/user.model.ts:26
- |
- ||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- this
-
-
-
-
- |
-
import { Deserializable } from '~shared/interfaces/deserializable.interface';
-import { Hero } from '../../hero/shared/hero.model';
-
-export enum Role {
- ADMIN = 'ADMIN',
- USER = 'USER',
-}
-
-export class User implements Deserializable {
- id: string;
- email: string;
- firstname: string;
- lastname: string;
- role: Role;
- heroes: Hero[];
-
- constructor(user: any = {}) {
- this.id = user.id;
- this.email = user.email;
- this.firstname = user.firstname;
- this.lastname = user.lastname;
- this.role = user.role;
- this.heroes = user.heroes;
- }
-
- deserialize(input: any) {
- Object.assign(this, input);
- return this;
- }
-}
-
- -
- src/app/app.component.ts
-
-
- OnInit
-
| selector | -app-root |
-
| templateUrl | -./app.component.html |
-
- Properties- |
-
-
|
-
- Methods- |
-
-
|
-
-constructor(title: Title, meta: Meta, snackBar: MatSnackBar, router: Router, renderer: Renderer2, doc: Document, locale: string)
- |
- ||||||||||||||||||||||||
|
- Defined in src/app/app.component.ts:16
- |
- ||||||||||||||||||||||||
|
-
- Parameters :
-
-
|
-
| - - - checkBrowser - - - | -
-checkBrowser()
- |
-
|
- Defined in src/app/app.component.ts:60
- |
-
|
-
-
- Returns :
- void
-
- |
-
| - - - checkBrowserFeatures - - - | -
-checkBrowserFeatures()
- |
-
|
- Defined in src/app/app.component.ts:68
- |
-
|
-
-
- Returns :
- boolean
-
- |
-
| - - - ngOnInit - - - | -
-ngOnInit()
- |
-
|
- Defined in src/app/app.component.ts:31
- |
-
|
-
-
- Returns :
- void
-
- |
-
| - - - onEvents - - - | -
-onEvents()
- |
-
|
- Defined in src/app/app.component.ts:38
- |
-
|
-
-
- Returns :
- void
-
- |
-
| - - - isOnline - - - | -
- Type : boolean
-
- |
-
|
- Defined in src/app/app.component.ts:16
- |
-
import { Component, Inject, LOCALE_ID, OnInit, Renderer2 } from '@angular/core';
-import { Meta, Title } from '@angular/platform-browser';
-import { NavigationEnd, Router } from '@angular/router';
-import { MatSnackBar } from '@angular/material/snack-bar';
-import { DOCUMENT } from '@angular/common';
-import { RoutesConfig } from './configs/routes.config';
-import { UtilsHelperService } from '~app/modules/core/services/utils-helper.service';
-
-declare const Modernizr: any;
-
-@Component({
- selector: 'app-root',
- templateUrl: './app.component.html',
-})
-export class AppComponent implements OnInit {
- isOnline: boolean;
-
- constructor(
- private title: Title,
- private meta: Meta,
- private snackBar: MatSnackBar,
- private router: Router,
- private renderer: Renderer2,
- @Inject(DOCUMENT) doc: Document,
- @Inject(LOCALE_ID) locale: string
- ) {
- this.isOnline = navigator.onLine;
- renderer.setAttribute(doc.documentElement, 'lang', locale);
- }
-
- ngOnInit() {
- this.title.setTitle('App title');
-
- this.onEvents();
- this.checkBrowser();
- }
-
- onEvents() {
- this.router.events.subscribe((event: any) => {
- if (event instanceof NavigationEnd) {
- switch (event.urlAfterRedirects) {
- case '/':
- this.meta.updateTag({
- name: 'description',
- content: 'Home meta description',
- });
- break;
- case '/' + RoutesConfig.routesNames.hero.basePath:
- this.title.setTitle('Heroes list');
- this.meta.updateTag({
- name: 'description',
- content: 'Heroes meta description',
- });
- break;
- }
- }
- });
- }
-
- checkBrowser() {
- if (UtilsHelperService.isBrowserValid()) {
- this.checkBrowserFeatures();
- } else {
- this.snackBar.open('Change your browser', 'OK');
- }
- }
-
- checkBrowserFeatures() {
- let supported = true;
- for (const feature in Modernizr) {
- if (
- Modernizr.hasOwnProperty(feature) &&
- typeof Modernizr[feature] === 'boolean' &&
- Modernizr[feature] === false
- ) {
- supported = false;
- break;
- }
- }
-
- if (!supported) {
- this.snackBar.open('Update your browser', 'OK');
- }
-
- return supported;
- }
-}
-
- <div>
- <app-header></app-header>
- <router-outlet *ngIf="isOnline; else isOffline"></router-outlet>
- <ng-template #isOffline>
- <div>
- <p class="offline-error" i18n>Without connection we can not load anything!</p>
- </div>
- </ng-template>
-</div>
-<app-footer></app-footer>
-
- -
- src/app/modules/root/pages/error404-page/error404-page.component.ts
-
| selector | -app-error404-page |
-
| styleUrls | -./error404-page.component.scss |
-
| templateUrl | -./error404-page.component.html |
-
-constructor()
- |
-
| - - | -
import { Component } from '@angular/core';
-
-@Component({
- selector: 'app-error404-page',
- templateUrl: './error404-page.component.html',
- styleUrls: ['./error404-page.component.scss'],
-})
-export class Error404PageComponent {
- constructor() {}
-}
-
- <h1 class="header__title" i18n>404 Error</h1>
-<p class="explanation" i18n>May the force be with you</p>
-<img alt="404 image star wars" src="./assets/images/404.gif" />
-
-
- ./error404-page.component.scss
-
@import '../../../../styles/mixins';
-
-img {
- @include push--auto();
- display: block;
-}
-
-.explanation {
- margin: 1rem 0;
- text-align: center;
- font-size: 1.2rem;
- font-weight: 300;
-}
-
- -
- src/app/modules/root/shared/footer/footer.component.ts
-
| selector | -app-footer |
-
| styleUrls | -./footer.component.scss |
-
| templateUrl | -./footer.component.html |
-
-constructor()
- |
-
| - - | -
import { Component } from '@angular/core';
-
-@Component({
- selector: 'app-footer',
- templateUrl: './footer.component.html',
- styleUrls: ['./footer.component.scss'],
-})
-export class FooterComponent {
- constructor() {}
-}
-
- <footer>
- <div
- fxFlex
- fxLayout="row"
- fxLayout.xs="column"
- fxLayoutAlign="center center"
- class.xs="footer-xs"
- >
- <div fxFlex="33">
- <span i18n>Angular Example App</span>
- </div>
- <div fxFlex="33" class="text--center">
- <lib-ngx-example-library></lib-ngx-example-library>
- </div>
- <div fxFlex class="text--right" class.xs="footer-xs">
- <a href="https://angular.io/" rel="noreferrer" target="_blank">
- <img alt="angular logo" src="./assets/images/angular.svg" />
- </a>
- </div>
- </div>
-</footer>
-
-
- ./footer.component.scss
-
@import '../../../../styles/mixins';
-
-footer {
- padding: calculateRem(8px) calculateRem(16px);
- color: $secondary--color;
- background: $primary--color;
- margin-top: 2rem;
- position: sticky;
- top: 100%;
-
- img {
- width: 25%;
- }
-}
-
-.footer-xs {
- text-align: center;
- padding-top: 1rem;
-}
-
- -
- src/app/modules/root/shared/header/header.component.ts
-
-
- OnInit
-
| selector | -app-header |
-
| styleUrls | -./header.component.scss |
-
| templateUrl | -./header.component.html |
-
- Properties- |
-
-
|
-
- Methods- |
-
-
|
-
-constructor(appConfig: any, routesConfig: any, storageService: StorageService, authService: AuthService, router: Router)
- |
- ||||||||||||||||||
| - - | -||||||||||||||||||
|
-
- Parameters :
-
-
|
-
| - - - changeLanguage - - - | -||||||
-changeLanguage(language: string)
- |
- ||||||
| - - | -||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- void
-
-
-
-
- |
-
| - - - logOut - - - | -
-logOut()
- |
-
| - - | -
|
-
-
- Returns :
- void
-
- |
-
| - - - ngOnInit - - - | -
-ngOnInit()
- |
-
| - - | -
|
-
-
- Returns :
- void
-
- |
-
| - - - Public - appConfig - - - | -
- Type : any
-
- |
-
|
- Decorators :
- -
- @Inject(APP_CONFIG)
- |
-
| - - | -
| - - - currentUrl - - - | -
- Type : string
-
- |
-
| - - | -
| - - - isLoggedIn - - - | -
- Type : boolean
-
- |
-
| - - | -
| - - - languages - - - | -
- Type : any[]
-
- |
-
| - - | -
| - - - Public - routesConfig - - - | -
- Type : any
-
- |
-
|
- Decorators :
- -
- @Inject(ROUTES_CONFIG)
- |
-
| - - | -
| - - - selectedLanguage - - - | -
- Type : string
-
- |
-
| - - | -
import { Component, Inject, OnInit } from '@angular/core';
-import { APP_CONFIG } from '~app/configs/app.config';
-import { NavigationEnd, Router } from '@angular/router';
-import { ROUTES_CONFIG, RoutesConfig } from '~app/configs/routes.config';
-import { AuthService } from '../../../auth/auth.service';
-import { StorageService } from '~shared/services/storage.service';
-
-@Component({
- selector: 'app-header',
- templateUrl: './header.component.html',
- styleUrls: ['./header.component.scss'],
-})
-export class HeaderComponent implements OnInit {
- selectedLanguage: string;
- currentUrl: string;
- languages: any[];
- isLoggedIn: boolean;
-
- constructor(
- @Inject(APP_CONFIG) public appConfig: any,
- @Inject(ROUTES_CONFIG) public routesConfig: any,
- private storageService: StorageService,
- private authService: AuthService,
- private router: Router
- ) {
- this.selectedLanguage = '';
- this.currentUrl = '';
- this.languages = [
- { name: 'en', label: 'English' },
- { name: 'es', label: 'Español' },
- ];
- this.isLoggedIn = this.authService.isLoggedIn();
- }
-
- ngOnInit() {
- this.selectedLanguage = this.storageService.getCookie('language') || 'en';
- this.router.events.subscribe(event => {
- if (event instanceof NavigationEnd) {
- this.currentUrl = event.url;
- this.isLoggedIn = this.authService.isLoggedIn();
- }
- });
- }
-
- changeLanguage(language: string): void {
- this.storageService.setCookie('language', language);
- this.selectedLanguage = language;
- }
-
- logOut(): void {
- this.storageService.removeCookie('accessToken');
- this.isLoggedIn = this.authService.isLoggedIn();
- this.router.navigate([RoutesConfig.routes.home]);
- }
-}
-
- <header>
- <nav>
- <div fxFlex fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center center">
- <div fxFlex="40">
- <a mat-raised-button [routerLink]="routesConfig.routes.home" i18n> Home </a>
- <a
- mat-raised-button
- *ngIf="isLoggedIn"
- [routerLink]="routesConfig.routes.hero.myHeroes"
- i18n
- >My Heroes</a
- >
- </div>
- <div fxFlex class="text--right">
- <app-search-bar></app-search-bar>
- <button aria-label="select language button" mat-icon-button [matMenuTriggerFor]="matmenu">
- <mat-icon>language</mat-icon>
- </button>
- <mat-menu #matmenu="matMenu">
- <div mat-menu-item *ngFor="let lang of languages">
- <a
- class="language-link"
- href="{{ lang.name === 'en' ? currentUrl : '/' + lang.name + currentUrl }}"
- (click)="changeLanguage(lang.name)"
- >
- <mat-icon>flag</mat-icon>
- <span>{{ lang.label }}</span>
- </a>
- </div>
- </mat-menu>
- <a
- mat-raised-button
- *ngIf="!isLoggedIn"
- [routerLink]="routesConfig.routes.auth.signUp"
- i18n
- >
- Sign Up
- </a>
- <a mat-raised-button *ngIf="!isLoggedIn" [routerLink]="routesConfig.routes.auth.logIn" i18n>
- Log In
- </a>
- <a mat-raised-button *ngIf="isLoggedIn" (click)="logOut()"> Log out </a>
- </div>
- </div>
- </nav>
-</header>
-
-
- ./header.component.scss
-
@import '../../../../styles/mixins';
-
-:host(app-header) {
- padding-top: 0;
- padding-bottom: 6.5rem;
- display: grid;
-
- header {
- position: fixed;
- z-index: 999;
- width: 100%;
-
- nav {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- padding: 0 calculateRem(16px);
- color: $secondary--color;
- height: 4rem;
- background: $primary--color;
-
- .mat-raised-button {
- color: $primary--color;
- margin-right: 1rem;
- }
-
- .progress-bar {
- display: flex;
- align-content: center;
- align-items: center;
- height: calculateRem(5px);
- }
-
- a {
- text-transform: uppercase;
- }
-
- .icon__image {
- width: calculateRem(20px);
- height: calculateRem(20px);
- }
-
- img {
- vertical-align: middle;
- }
-
- #today {
- font-size: 0.7rem;
- }
-
- #logo {
- display: flex;
- margin-right: 1rem;
-
- a {
- width: 4.25rem;
- height: 4.25rem;
-
- img {
- width: 100%;
- height: auto;
- opacity: 0.8;
-
- &:hover {
- opacity: 1;
- }
- }
- }
- }
- }
- }
-}
-
-@media (max-width: 807px) {
- #today {
- width: 50%;
- }
-
- #logo {
- display: none;
- }
-}
-
-@media (max-width: 680px) {
- :host(app-header) {
- padding-top: 0;
- padding-bottom: 1rem;
-
- header {
- position: relative;
-
- nav {
- height: 7rem;
- display: flex;
- padding: 1rem 2rem 0;
-
- > div {
- margin-top: 1rem;
- }
-
- #today {
- margin-top: 1rem;
- }
- }
- }
- }
-}
-
-@media (max-width: 425px) {
- :host(app-header) {
- padding-bottom: 0;
-
- header {
- nav {
- app-search-bar {
- width: 75%;
- }
- }
- }
- }
-}
-
- -
- src/app/shared/components/hero-card/hero-card.component.ts
-
| changeDetection | -ChangeDetectionStrategy.OnPush |
-
| selector | -app-hero-card |
-
| styleUrls | -./hero-card.component.scss |
-
| templateUrl | -./hero-card.component.html |
-
- Properties- |
-
-
|
-
- Methods- |
-
-
|
-
- Inputs- |
-
-
|
-
-constructor(heroService: HeroService, router: Router, utilsService: UtilsService, authService: AuthService, eventsService: EventsService, routesConfig: any)
- |
- |||||||||||||||||||||
| - - | -|||||||||||||||||||||
|
-
- Parameters :
-
-
|
-
| - - hero - | -|
- Type : Hero | undefined
-
- |
- |
| - - | -|
| - - - like - - - | -||||||
-like(hero: Hero)
- |
- ||||||
| - - | -||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- Promise | void
-
-
-
-
- |
-
| - - - Public - routesConfig - - - | -
- Type : any
-
- |
-
|
- Decorators :
- -
- @Inject(ROUTES_CONFIG)
- |
-
| - - | -
import { ChangeDetectionStrategy, Component, Inject, Input } from '@angular/core';
-import { Hero } from '~modules/hero/shared/hero.model';
-import { transition, trigger, useAnimation } from '@angular/animations';
-import { fadeIn } from 'ng-animate';
-import { ROUTES_CONFIG, RoutesConfig } from '~app/configs/routes.config';
-import { HeroService } from '~modules/hero/shared/hero.service';
-import { Router } from '@angular/router';
-import { AuthService } from '~modules/auth/auth.service';
-import { UtilsService } from '../../services/utils.service';
-import { EventsService, EventsTypes } from '~modules/core/services/events.servide';
-
-@Component({
- selector: 'app-hero-card',
- templateUrl: './hero-card.component.html',
- styleUrls: ['./hero-card.component.scss'],
- changeDetection: ChangeDetectionStrategy.OnPush,
- animations: [
- trigger('fadeIn', [
- transition(
- '* => *',
- useAnimation(fadeIn, {
- params: { timing: 1, delay: 0 },
- })
- ),
- ]),
- ],
-})
-export class HeroCardComponent {
- @Input() hero: Hero | undefined;
-
- constructor(
- private heroService: HeroService,
- private router: Router,
- private utilsService: UtilsService,
- private authService: AuthService,
- private eventsService: EventsService,
- @Inject(ROUTES_CONFIG) public routesConfig: any
- ) {}
-
- like(hero: Hero): Promise<void> | void {
- if (this.authService.isLoggedIn()) {
- this.heroService.voteHero(hero).subscribe(response => {
- if (!response.errors) {
- this.eventsService.send({ type: EventsTypes.UPDATE_HEROES });
- } else {
- this.utilsService.showSnackBar(response.errors[0].message, 'warning-snack-bar');
- }
- });
- } else {
- this.router.navigate([RoutesConfig.routes.auth.logIn]);
- }
- }
-}
-
- <mat-card class="hero-card" *ngIf="hero" [@fadeIn]="'fadeIn'">
- <mat-card-header>
- <mat-card-title>
- <a class="hero-detail-link" [routerLink]="[routesConfig.routes.hero.detail(hero.id)]">
- {{ hero.alterEgo }}
- </a>
- </mat-card-title>
- <mat-card-subtitle>
- <a class="hero-detail-link" [routerLink]="[routesConfig.routes.hero.detail(hero.id)]">
- {{ hero.realName }}
- </a>
- </mat-card-subtitle>
- <div class="flex-spacer"></div>
- <div class="hero-actions">
- {{ hero.usersVoted.length }}
- <mat-icon class="icon__like--red" (click)="like(hero)">favorite </mat-icon>
- </div>
- </mat-card-header>
- <a class="hero-detail-link" [routerLink]="[routesConfig.routes.hero.detail(hero.id)]">
- <img alt="{{ hero.realName }} hero image" [defaultImage]="hero.image" [lazyLoad]="hero.image" />
- </a>
-</mat-card>
-
-
- ./hero-card.component.scss
-
@import '../../../styles/mixins';
-@import '../../../styles/colors';
-
-.hero-detail-link {
- @include text-small-grey();
-}
-
-mat-card-title,
-mat-card-subtitle,
-.mat-card-image {
- cursor: pointer;
-}
-
-.hero-card {
- margin-bottom: 2rem;
- @include push--auto(2rem);
-}
-
-.progress__spinner {
- @include push--auto();
-}
-
-img {
- width: 100%;
- height: auto;
-}
-
-@media (max-width: 680px) {
- .hero-card {
- width: 80%;
- @include push--auto();
- }
-
- .mat-card {
- margin-bottom: 2rem;
- }
-}
-
- -
- src/app/modules/hero/pages/hero-detail-page/hero-detail-page.component.ts
-
-
- OnInit
-
| selector | -app-hero-detail-page |
-
| styleUrls | -./hero-detail-page.component.scss |
-
| templateUrl | -./hero-detail-page.component.html |
-
- Properties- |
-
-
|
-
- Methods- |
-
-
|
-
-constructor(location: Location, router: Router, activatedRoute: ActivatedRoute)
- |
- ||||||||||||
| - - | -||||||||||||
|
-
- Parameters :
-
-
|
-
| - - - goBack - - - | -
-goBack()
- |
-
| - - | -
|
-
-
- Returns :
- void
-
- |
-
| - - - goToTheAnchor - - - | -
-goToTheAnchor()
- |
-
| - - | -
|
-
-
- Returns :
- void
-
- |
-
| - - - ngOnInit - - - | -
-ngOnInit()
- |
-
| - - | -
|
-
-
- Returns :
- void
-
- |
-
| - - - hero - - - | -
- Type : Hero | undefined
-
- |
-
| - - | -
import { Component, OnInit } from '@angular/core';
-import { Hero } from '../../shared/hero.model';
-import { ActivatedRoute, Router } from '@angular/router';
-import { Location } from '@angular/common';
-import { transition, trigger, useAnimation } from '@angular/animations';
-import { fadeIn } from 'ng-animate';
-import { RoutesConfig } from '../../../../configs/routes.config';
-
-@Component({
- selector: 'app-hero-detail-page',
- templateUrl: './hero-detail-page.component.html',
- styleUrls: ['./hero-detail-page.component.scss'],
- animations: [
- trigger('fadeIn', [
- transition(
- '* => *',
- useAnimation(fadeIn, {
- params: { timing: 1, delay: 0 },
- })
- ),
- ]),
- ],
-})
-export class HeroDetailPageComponent implements OnInit {
- hero: Hero | undefined;
-
- constructor(
- private location: Location,
- private router: Router,
- private activatedRoute: ActivatedRoute
- ) {}
-
- ngOnInit() {
- this.activatedRoute.snapshot.data['hero'].subscribe((hero: Hero) => {
- this.hero = hero;
- });
- }
-
- goBack(): void {
- this.location.back();
- }
-
- goToTheAnchor(): void {
- if (this.hero) {
- this.router.navigate([RoutesConfig.routes.hero.detail(this.hero.id)], {
- fragment: 'heroe-detail',
- });
- }
- }
-}
-
- <h1 class="header__title" i18n>Hero detail</h1>
-<div class="container" *ngIf="!hero">
- <app-hero-loading></app-hero-loading>
-</div>
-<div class="container" *ngIf="hero" [@fadeIn]="'fadeIn'">
- <ng-container>
- <app-hero-card [hero]="hero"></app-hero-card>
- <div id="hero-json">
- <pre>{{ hero | json }}</pre>
- </div>
- </ng-container>
-</div>
-<button
- *ngIf="hero"
- aria-label="Anchor the hero button"
- mat-raised-button
- type="button"
- (click)="goToTheAnchor()"
- i18n
->
- Anchor the hero
-</button>
-<button aria-label="Go back button" mat-raised-button type="button" (click)="goBack()" i18n>
- Go back
-</button>
-
-
- ./hero-detail-page.component.scss
-
@import '../../../../styles/mixins';
-
-.container {
- width: 65%;
- @include push--auto();
- margin-top: 2rem;
-}
-
-button {
- @include push--auto(2rem);
- display: block;
-}
-
-@media (max-width: 600px) {
- .container {
- width: 90%;
- }
-}
-
- -
- src/app/shared/components/hero-loading/hero-loading.component.ts
-
| selector | -app-hero-loading |
-
| styleUrls | -./hero-loading.component.scss |
-
| templateUrl | -./hero-loading.component.html |
-
-constructor()
- |
-
| - - | -
import { Component } from '@angular/core';
-
-@Component({
- selector: 'app-hero-loading',
- templateUrl: './hero-loading.component.html',
- styleUrls: ['./hero-loading.component.scss'],
-})
-export class HeroLoadingComponent {
- constructor() {}
-}
-
- <mat-card id="loading-card" class="hero-card">
- <mat-card-header>
- <div mat-card-avatar class="hero-header__image"></div>
- <mat-card-title>
- <app-loading-placeholder [width]="'200px'" [height]="'1rem'"></app-loading-placeholder>
- </mat-card-title>
- <mat-card-subtitle>
- <app-loading-placeholder [width]="'160px'" [height]="'1rem'"></app-loading-placeholder>
- </mat-card-subtitle>
- <div class="flex-spacer"></div>
- <div class="hero-actions">
- <mat-icon class="icon__like--grey">favorite</mat-icon>
- </div>
- </mat-card-header>
- <app-loading-placeholder [height]="'486px'"></app-loading-placeholder>
-</mat-card>
-
-
- ./hero-loading.component.scss
-
@import '../../../styles/colors';
-
-.hero-header__image {
- background: $grey;
-}
-
- -
- src/app/modules/hero/components/hero-remove/hero-remove.component.ts
-
| selector | -app-hero-remove |
-
| templateUrl | -./hero-remove.component.html |
-
-constructor()
- |
-
| - - | -
import { Component } from '@angular/core';
-
-@Component({
- selector: 'app-hero-remove',
- templateUrl: './hero-remove.component.html',
-})
-export class HeroRemoveComponent {
- constructor() {}
-}
-
- <h2 mat-dialog-title i18n>Delete hero</h2>
-<mat-dialog-content i18n>Are you sure?</mat-dialog-content>
-<mat-dialog-actions>
- <button aria-label="no button" mat-button mat-dialog-close i18n>No</button>
- <button aria-label="yes button" mat-button [mat-dialog-close]="true" i18n>Yes</button>
-</mat-dialog-actions>
-
- -
- src/app/modules/root/pages/home-page/home-page.component.ts
-
-
- OnInit
-
| selector | -app-home-page |
-
| styleUrls | -./home-page.component.scss |
-
| templateUrl | -./home-page.component.html |
-
- Properties- |
-
-
|
-
- Methods- |
-
-
|
-
-constructor(heroService: HeroService, eventsService: EventsService)
- |
- |||||||||
| - - | -|||||||||
|
-
- Parameters :
-
-
|
-
| - - - ngOnInit - - - | -
-ngOnInit()
- |
-
| - - | -
|
-
-
- Returns :
- void
-
- |
-
| - - - heroes$ - - - | -
- Type : Observable<Hero[]> | undefined
-
- |
-
| - - | -
import { Component, OnInit } from '@angular/core';
-import { Hero } from '../../../hero/shared/hero.model';
-import { Observable } from 'rxjs';
-import { HeroService } from '../../../hero/shared/hero.service';
-import { EventsService, EventsTypes } from '../../../core/services/events.servide';
-
-@Component({
- selector: 'app-home-page',
- templateUrl: './home-page.component.html',
- styleUrls: ['./home-page.component.scss'],
-})
-export class HomePageComponent implements OnInit {
- heroes$: Observable<Hero[]> | undefined;
-
- constructor(private heroService: HeroService, private eventsService: EventsService) {
- // @ts-ignore
- if (window.Cypress) {
- // @ts-ignore
- window.HomePageComponent = this;
- }
- }
-
- ngOnInit() {
- this.heroes$ = this.heroService.searchHeroes({ fetchPolicy: 'no-cache' });
-
- this.eventsService.events$.subscribe(event => {
- if (event.type === EventsTypes.UPDATE_HEROES) {
- this.heroes$ = this.heroService.searchHeroes({ fetchPolicy: 'no-cache' });
- }
- });
- }
-}
-
- <div fxLayout="row">
- <div fxFlex="10" fxFlex.gt-sm="20"></div>
- <div fxFlex="90" fxFlex.gt-sm="80">
- <h1 class="header__title" i18n>Heroes published</h1>
- <div id="heroes-list" *ngIf="heroes$ | async as heroes; else loading">
- <ng-container *ngFor="let hero of heroes">
- <app-hero-card [hero]="hero"></app-hero-card>
- </ng-container>
- </div>
- <ng-template #loading>
- <app-hero-loading></app-hero-loading>
- </ng-template>
- </div>
- <div fxFlex="10" fxFlex.gt-sm="20"></div>
-</div>
-
-
- ./home-page.component.scss
-
mat-card-title,
-mat-card-subtitle,
-.mat-card-image {
- cursor: pointer;
-}
-
- -
- src/app/shared/components/loading-placeholder/loading-placeholder.component.ts
-
| selector | -app-loading-placeholder |
-
| styleUrls | -./loading-placeholder.component.scss |
-
| templateUrl | -./loading-placeholder.component.html |
-
- Inputs- |
-
| - - | -
-constructor()
- |
-
| - - | -
| - - height - | -|
- Type : string
-
- |
- |
- Default value : ''
- |
- |
| - - | -|
| - - width - | -|
- Type : string
-
- |
- |
- Default value : ''
- |
- |
| - - | -|
import { Component, Input } from '@angular/core';
-
-@Component({
- selector: 'app-loading-placeholder',
- templateUrl: './loading-placeholder.component.html',
- styleUrls: ['./loading-placeholder.component.scss'],
-})
-export class LoadingPlaceholderComponent {
- @Input() height = '';
- @Input() width = '';
-
- constructor() {}
-}
-
- <div class="placeholder-animation" [ngStyle]="{ height: height, width: width }"></div>
-
-
- ./loading-placeholder.component.scss
-
@import 'src/app/styles/colors';
-
-@keyframes placeHolderShimmer {
- 0% {
- background-position: -468px 0;
- }
- 100% {
- background-position: 468px 0;
- }
-}
-
-.placeholder-animation {
- animation-duration: 1.25s;
- animation-fill-mode: forwards;
- animation-iteration-count: infinite;
- animation-name: placeHolderShimmer;
- animation-timing-function: linear;
- background: darkgray;
- background: linear-gradient(to right, $light-grey 10%, #dddddd 18%, #eeeeee 33%);
- position: relative;
- background-size: 1000px 100px;
-}
-
- -
- src/app/modules/auth/pages/log-in-page/log-in-page.component.ts
-
| selector | -app-log-in-page |
-
| styleUrls | -./log-in-page.component.scss |
-
| templateUrl | -./log-in-page.component.html |
-
- Properties- |
-
| - - | -
- Methods- |
-
-
|
-
-constructor(formBuilder: FormBuilder, authService: AuthService, router: Router, utilsService: UtilsService)
- |
- |||||||||||||||
| - - | -|||||||||||||||
|
-
- Parameters :
-
-
|
-
| - - - getErrorMessage - - - | -||||||
-getErrorMessage(field: string)
- |
- ||||||
| - - | -||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- string | void
-
-
-
-
- |
-
| - - - sendForm - - - | -
-sendForm()
- |
-
| - - | -
|
-
-
- Returns :
- void
-
- |
-
| - - - email - - - | -
- Default value : new FormControl('', [Validators.required, Validators.email])
- |
-
| - - | -
| - - - hide - - - | -
- Default value : true
- |
-
| - - | -
| - - - loginForm - - - | -
- Type : any
-
- |
-
|
- Decorators :
- -
- @ViewChild('loginForm')
- |
-
| - - | -
| - - - logInForm - - - | -
- Type : FormGroup
-
- |
-
| - - | -
| - - - password - - - | -
- Default value : new FormControl('', [Validators.required])
- |
-
| - - | -
import { Component, ViewChild } from '@angular/core';
-import { transition, trigger, useAnimation } from '@angular/animations';
-import { fadeIn } from 'ng-animate';
-import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
-import { AuthService } from '../../auth.service';
-import { RoutesConfig } from '../../../../configs/routes.config';
-import { Router } from '@angular/router';
-import { UtilsService } from '../../../../shared/services/utils.service';
-
-@Component({
- selector: 'app-log-in-page',
- templateUrl: './log-in-page.component.html',
- styleUrls: ['./log-in-page.component.scss'],
- animations: [
- trigger('fadeIn', [
- transition(
- '* => *',
- useAnimation(fadeIn, {
- params: { timing: 1, delay: 0 },
- })
- ),
- ]),
- ],
-})
-export class LogInPageComponent {
- @ViewChild('loginForm') loginForm: any;
-
- logInForm: FormGroup;
- email = new FormControl('', [Validators.required, Validators.email]);
- password = new FormControl('', [Validators.required]);
- hide = true;
-
- constructor(
- private formBuilder: FormBuilder,
- private authService: AuthService,
- private router: Router,
- private utilsService: UtilsService
- ) {
- this.logInForm = this.formBuilder.group({
- email: this.email,
- password: this.password,
- });
- }
-
- getErrorMessage(field: string): string | void {
- // @ts-ignore
- const classField = this[field];
- if (classField?.hasError('required')) {
- return 'You must enter a value';
- } else if (classField?.hasError('email')) {
- return 'Not a valid email';
- }
- }
-
- sendForm() {
- if (this.logInForm.valid) {
- const formValue = this.logInForm.value;
- this.authService.logIn(formValue.email, formValue.password).subscribe((response: any) => {
- if (!response.errors) {
- this.router.navigate([RoutesConfig.routes.hero.myHeroes]);
- } else if (response.errors[0].code === 11000) {
- this.utilsService.showSnackBar("Nice! Let's create some heroes", 'info-snack-bar');
- }
- });
- }
- }
-}
-
- <mat-grid-list cols="1" rows="1" rowHeight="2:1">
- <mat-grid-tile>
- <mat-card class="login--form__box--blue">
- <div class="login--form-container">
- <p class="login--form__header-title">Try to log in!</p>
- <form class="example-container" [formGroup]="logInForm" #loginForm="ngForm">
- <p>
- <mat-form-field appearance="outline">
- <mat-label>Enter your email</mat-label>
- <input matInput placeholder="pat@example.com" [formControl]="email" required />
- <mat-error *ngIf="email.invalid">{{ getErrorMessage('email') }}</mat-error>
- </mat-form-field>
- </p>
- <p>
- <mat-form-field appearance="outline">
- <mat-label>Enter a password</mat-label>
- <input matInput [formControl]="password" [type]="hide ? 'password' : 'text'" />
- <button
- mat-icon-button
- matSuffix
- (click)="hide = !hide"
- [attr.aria-label]="'Hide password'"
- [attr.aria-pressed]="hide"
- >
- <mat-icon>{{ hide ? 'visibility_off' : 'visibility' }}</mat-icon>
- </button>
- <mat-hint
- >Must be minimum eight characters, at least one uppercase letter, one lowercase
- letter and one number</mat-hint
- >
- <mat-error *ngIf="password.invalid">{{ getErrorMessage('password') }}</mat-error>
- </mat-form-field>
- </p>
- <p>
- <button
- class="login--form__submit-button"
- mat-raised-button
- color="primary"
- (click)="sendForm()"
- >
- {{ 'Log In' | uppercase }}
- </button>
- </p>
- </form>
- </div>
- </mat-card>
- </mat-grid-tile>
-</mat-grid-list>
-
-
- ./log-in-page.component.scss
-
@import '../../../../styles/mixins';
-
-.login--form-container {
- text-align: center;
-
- p {
- margin-bottom: 1rem;
- }
-
- .login--form__header-title {
- margin-bottom: 2rem;
- }
-}
-
-.login--form-container .mat-form-field + .mat-form-field {
- margin-left: 8px;
-}
-
-.mat-form-field {
- width: 100%;
-}
-
-.login--form__box--blue {
- padding: 4rem;
-}
-
-:host ::ng-deep .mat-form-field-flex {
- background: rgb(245, 245, 245);
-}
-
-.login--form__header-title {
- font-weight: bold;
- font-size: 20px;
- color: #000000de;
-}
-
-.login--form__submit-button {
- margin-top: 40px;
-}
-
- -
- src/app/modules/hero/pages/my-heroes-page/my-heroes-page.component.ts
-
-
- OnInit
-
| selector | -app-my-heroes-page |
-
| styleUrls | -./my-heroes-page.component.scss |
-
| templateUrl | -./my-heroes-page.component.html |
-
- Properties- |
-
-
|
-
- Methods- |
-
-
|
-
-constructor(heroService: HeroService, userService: UserService, dialog: MatDialog, snackBar: MatSnackBar, utilsService: UtilsService, router: Router, formBuilder: FormBuilder, routesConfig: any)
- |
- |||||||||||||||||||||||||||
| - - | -|||||||||||||||||||||||||||
|
-
- Parameters :
-
-
|
-
| - - - createNewHero - - - | -
-createNewHero()
- |
-
| - - | -
|
-
-
- Returns :
- void
-
- |
-
| - - - deleteHero - - - | -||||||
-deleteHero(hero: Hero)
- |
- ||||||
| - - | -||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- void
-
-
-
-
- |
-
| - - - loadUser - - - | -
-loadUser()
- |
-
| - - | -
|
-
-
- Returns :
- void
-
- |
-
| - - - ngOnInit - - - | -
-ngOnInit()
- |
-
| - - | -
|
-
-
- Returns :
- void
-
- |
-
| - - - Private - onChanges - - - | -
-
- onChanges()
- |
-
| - - | -
|
-
-
- Returns :
- void
-
- |
-
| - - - trackByFn - - - | -||||||
-trackByFn(index: any)
- |
- ||||||
| - - | -||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- any
-
-
-
-
- |
-
| - - - alterEgo - - - | -
- Type : FormControl
-
- |
-
| - - | -
| - - - error - - - | -
- Type : boolean
-
- |
-
| - - | -
| - - - myNgForm - - - | -
- Type : any
-
- |
-
- Default value : ''
- |
-
|
- Decorators :
- -
- @ViewChild('form', {static: false})
- |
-
| - - | -
| - - - newHeroForm - - - | -
- Type : any
-
- |
-
| - - | -
| - - - realName - - - | -
- Type : FormControl
-
- |
-
| - - | -
| - - - Public - routesConfig - - - | -
- Type : any
-
- |
-
|
- Decorators :
- -
- @Inject(ROUTES_CONFIG)
- |
-
| - - | -
| - - - user - - - | -
- Type : User | undefined
-
- |
-
| - - | -
import { Component, Inject, OnInit, ViewChild } from '@angular/core';
-import { Hero } from '../../shared/hero.model';
-import { FormBuilder, FormControl, Validators } from '@angular/forms';
-import { MatDialog } from '@angular/material/dialog';
-import { MatSnackBar } from '@angular/material/snack-bar';
-import { Router } from '@angular/router';
-import { HeroRemoveComponent } from '../../components/hero-remove/hero-remove.component';
-import { transition, trigger, useAnimation } from '@angular/animations';
-import { fadeIn } from 'ng-animate';
-import { ROUTES_CONFIG } from '../../../../configs/routes.config';
-import { HeroService } from '../../shared/hero.service';
-import { UtilsHelperService } from '../../../core/services/utils-helper.service';
-import { UserService } from '../../../user/user.service';
-import { User } from '../../../user/shared/user.model';
-import { UtilsService } from '../../../../shared/services/utils.service';
-
-@Component({
- selector: 'app-my-heroes-page',
- templateUrl: './my-heroes-page.component.html',
- styleUrls: ['./my-heroes-page.component.scss'],
- animations: [
- trigger('fadeIn', [
- transition(
- '* => *',
- useAnimation(fadeIn, {
- params: { timing: 1, delay: 0 },
- })
- ),
- ]),
- ],
-})
-export class MyHeroesPageComponent implements OnInit {
- user: User | undefined;
- newHeroForm: any;
- error: boolean;
- realName: FormControl;
- alterEgo: FormControl;
-
- @ViewChild('form', { static: false }) myNgForm: any = ''; // just to call resetForm method
-
- constructor(
- private heroService: HeroService,
- private userService: UserService,
- private dialog: MatDialog,
- private snackBar: MatSnackBar,
- private utilsService: UtilsService,
- private router: Router,
- private formBuilder: FormBuilder,
- @Inject(ROUTES_CONFIG) public routesConfig: any
- ) {
- this.error = false;
- this.realName = new FormControl('', [Validators.required, Validators.maxLength(30)]);
- this.alterEgo = new FormControl('', [Validators.required, Validators.maxLength(30)]);
- this.newHeroForm = this.formBuilder.group({
- realName: this.realName,
- alterEgo: this.alterEgo,
- });
-
- this.onChanges();
- }
-
- ngOnInit() {
- this.loadUser();
- }
-
- loadUser() {
- this.userService.getMe({ fetchPolicy: 'no-cache' }).subscribe((user: User) => {
- this.user = user;
- });
- }
-
- createNewHero() {
- if (this.newHeroForm.valid) {
- this.heroService.createHero(new Hero(this.newHeroForm.value)).subscribe(response => {
- if (!response.errors) {
- this.myNgForm.resetForm();
- this.utilsService.showSnackBar('Hero created', 'info-snack-bar');
- this.loadUser();
- }
- });
- }
- }
-
- deleteHero(hero: Hero) {
- const dialogRef = this.dialog.open(HeroRemoveComponent);
- dialogRef.afterClosed().subscribe(result => {
- if (result) {
- this.heroService.removeHero(hero.id).subscribe(response => {
- if (!response.errors) {
- this.utilsService.showSnackBar('Hero removed', 'info-snack-bar');
- this.loadUser();
- } else {
- this.error = true;
- }
- });
- }
- });
- }
-
- trackByFn(index: any) {
- return index;
- }
-
- private onChanges() {
- this.newHeroForm.get('realName')?.valueChanges.subscribe((value: any) => {
- if (value && value.length >= 3 && UtilsHelperService.isPalindrome(value)) {
- this.snackBar.open("Yeah that's a Palindrome!", '', { duration: 2000 });
- } else {
- this.snackBar.dismiss();
- }
- });
- }
-}
-
- <div id="left">
- <h2 class="header__title" i18n>My heroes</h2>
- <p *ngIf="!user?.heroes?.length" class="my-heroes__no-heroes--message" i18n>
- No heroes yet, try to create one in the right side!
- </p>
- <div>
- <mat-list id="loading-list" *ngIf="!user?.heroes">
- <mat-list-item *ngFor="let i of [1, 2, 3, 4, 5, 6, 7, 8]">
- <img alt="default hero avatar" mat-list-avatar src="./assets/images/default-hero.png" />
- <h3 mat-line>
- <app-loading-placeholder [width]="'150px'" [height]="'0.9rem'"></app-loading-placeholder>
- </h3>
- <p mat-line>
- <app-loading-placeholder [width]="'100px'" [height]="'0.9rem'"></app-loading-placeholder>
- </p>
- <div class="hero-actions">
- <app-loading-placeholder [width]="'30px'" [height]="'0.9rem'"></app-loading-placeholder>
-
- <mat-icon class="icon__like--grey">favorite</mat-icon>
- </div>
- </mat-list-item>
- </mat-list>
- <mat-list>
- <mat-list-item *ngFor="let hero of user?.heroes; trackBy: trackByFn">
- <h3 mat-line [class.cp]="hero.published">
- {{ hero.alterEgo }}
- </h3>
- <p mat-line [class.cp]="hero.published">
- <span>{{ hero.realName }}</span>
- </p>
- <div class="hero-actions">
- <mat-icon class="icon__remove" *ngIf="!hero.published" (click)="deleteHero(hero)">
- delete
- </mat-icon>
- </div>
- </mat-list-item>
- </mat-list>
- </div>
-</div>
-<div id="right">
- <h2 class="header__title" i18n>Create a hero</h2>
- <div id="form-loading" *ngIf="!user?.heroes">
- <form>
- <div class="input-container">
- <app-loading-placeholder [height]="'2rem'"></app-loading-placeholder>
- </div>
- <div class="input-container">
- <app-loading-placeholder [height]="'2rem'"></app-loading-placeholder>
- </div>
-
- <button aria-label="create button" mat-raised-button [disabled]="true" i18n>Create</button>
- </form>
- </div>
- <div *ngIf="user?.heroes">
- <form
- [formGroup]="newHeroForm"
- #form="ngForm"
- ngxScrollToFirstInvalid
- (ngSubmit)="createNewHero()"
- autocomplete="on"
- >
- <mat-form-field class="input-container">
- <input
- matInput
- name="hname"
- type="text"
- placeholder="Name (Palindrome?)"
- i18n-placeholder="@@nameWithPalindrome"
- formControlName="realName"
- />
- <mat-error *ngIf="realName.errors && form.submitted">
- <ng-template [ngIf]="realName.errors['required']" i18n> Name is required </ng-template>
- <ng-template [ngIf]="realName.errors['maxlength']" i18n>
- The field is too long
- </ng-template>
- </mat-error>
- </mat-form-field>
- <mat-form-field class="input-container">
- <input
- matInput
- type="text"
- name="rname"
- placeholder="Alter ego"
- i18n-placeholder="@@realName"
- formControlName="alterEgo"
- />
- <mat-error *ngIf="alterEgo.errors && form.submitted">
- <ng-template [ngIf]="alterEgo.errors['required']" i18n> Name is required </ng-template>
- <ng-template [ngIf]="alterEgo.errors['maxlength']" i18n>
- The field is too long. Required length:
- {{ alterEgo.errors['maxlength'].requiredLength }}. Current:
- {{ alterEgo.errors['maxlength'].actualLength }}
- </ng-template>
- </mat-error>
- </mat-form-field>
- <button
- aria-label="create button"
- mat-raised-button
- type="submit"
- [disabled]="form.submitted && !newHeroForm.valid"
- i18n
- >
- Create
- </button>
- <div *ngIf="error" i18n>An error has ocurred</div>
- </form>
- </div>
-
- <div id="heroes-json">
- <h2 class="header__title" i18n>Heroes 1 and 2</h2>
- <pre *ngIf="!user?.heroes">
- <app-loading-placeholder [height]="'300px'"></app-loading-placeholder>
- </pre>
- <pre *ngIf="user?.heroes">{{ user?.heroes | slice: 0:2 | json }}</pre>
- </div>
-</div>
-<div class="clear"></div>
-
-
- ./my-heroes-page.component.scss
-
@import 'src/app/styles/mixins';
-@import 'src/app/styles/colors';
-
-a {
- @include text-small-grey();
-}
-
-#loading-list {
- p {
- margin-top: 0.2rem;
- }
-}
-
-#form-loading {
- .input-container {
- margin: 0.5rem 0;
- }
-}
-
-#left {
- width: 50%;
- float: left;
- margin-left: 6%;
-}
-
-#right {
- margin-left: 50%;
- text-align: center;
- padding-right: 17%;
-}
-
-.clear {
- clear: both;
-}
-
-.mat-list {
- @include push--auto();
- display: table;
-
- .mat-list-text {
- text-align: left !important;
- }
-}
-
-.hero-actions {
- margin-left: 1rem;
- padding-bottom: 0;
-
- .icon__remove {
- padding-left: 0.5rem;
- color: darkslategrey;
- cursor: pointer;
- }
-}
-
-form {
- display: grid;
- width: 80%;
- @include push--auto();
-
- .mat-raised-button {
- color: $secondary--color;
- background: $primary--color;
- width: 50%;
- @include push--auto();
- }
-
- .mat-form-field {
- width: 100%;
- }
-}
-
-#heroes-json {
- margin-top: 2rem;
-
- pre {
- margin-top: 1rem;
- }
-}
-
-.my-heroes__no-heroes--message {
- text-align: center;
- width: 20%;
- margin: 0 auto;
- line-height: 1.7rem;
-}
-
-@media (max-width: 680px) {
- #left {
- width: 100%;
- float: none;
- @include push--auto();
- }
-
- #right {
- margin: 1em auto 0;
- width: 90%;
- float: none;
- padding: 0;
- }
-}
-
- -
- src/app/modules/root/shared/search-bar/search-bar.component.ts
-
-
- OnInit
-
| selector | -app-search-bar |
-
| styleUrls | -./search-bar.component.scss |
-
| templateUrl | -./search-bar.component.html |
-
- Properties- |
-
-
|
-
- Methods- |
-
-
|
-
-constructor(heroService: HeroService, routesConfig: any)
- |
- |||||||||
| - - | -|||||||||
|
-
- Parameters :
-
-
|
-
| - - - filterHeroes - - - | -||||||
-filterHeroes(val: string)
- |
- ||||||
| - - | -||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- Hero[]
-
-
-
-
- |
-
| - - - ngOnInit - - - | -
-ngOnInit()
- |
-
| - - | -
|
-
-
- Returns :
- void
-
- |
-
| - - - defaultHeroes - - - | -
- Type : Array<Hero>
-
- |
-
| - - | -
| - - - filteredHeroes - - - | -
- Type : any
-
- |
-
| - - | -
| - - - heroFormControl - - - | -
- Type : FormControl
-
- |
-
| - - | -
| - - - Public - routesConfig - - - | -
- Type : any
-
- |
-
|
- Decorators :
- -
- @Inject(ROUTES_CONFIG)
- |
-
| - - | -
import { map, startWith } from 'rxjs/operators';
-import { Component, Inject, OnInit } from '@angular/core';
-import { FormControl } from '@angular/forms';
-import { Hero } from '../../../hero/shared/hero.model';
-import { ROUTES_CONFIG } from '~app/configs/routes.config';
-import { HeroService } from '../../../hero/shared/hero.service';
-
-@Component({
- selector: 'app-search-bar',
- templateUrl: './search-bar.component.html',
- styleUrls: ['./search-bar.component.scss'],
-})
-export class SearchBarComponent implements OnInit {
- defaultHeroes: Array<Hero>;
- heroFormControl: FormControl;
- filteredHeroes: any;
-
- constructor(private heroService: HeroService, @Inject(ROUTES_CONFIG) public routesConfig: any) {
- this.defaultHeroes = [];
- this.heroFormControl = new FormControl();
- }
-
- ngOnInit() {
- this.heroService.searchHeroes({ fetchPolicy: 'no-cache' }).subscribe((heroes: Array<Hero>) => {
- this.defaultHeroes = heroes;
-
- this.heroFormControl.valueChanges
- .pipe(
- startWith(null as unknown as string),
- map(value => this.filterHeroes(value))
- )
- .subscribe(heroesFiltered => {
- this.filteredHeroes = heroesFiltered;
- });
- });
- }
-
- filterHeroes(val: string): Hero[] {
- return val
- ? this.defaultHeroes.filter(
- hero => hero.alterEgo.toLowerCase().indexOf(val.toLowerCase()) === 0
- )
- : this.defaultHeroes;
- }
-}
-
- <mat-form-field id="search-input">
- <input
- matInput
- placeholder="Look for a hero!"
- i18n-placeholder
- [matAutocomplete]="heroesAutocomplete"
- [formControl]="heroFormControl"
- />
-</mat-form-field>
-
-<mat-autocomplete #heroesAutocomplete="matAutocomplete">
- <mat-option *ngFor="let hero of filteredHeroes" [value]="hero.name">
- <a class="hero-link" [routerLink]="[routesConfig.routes.hero.detail(hero.id)]">
- {{ hero.alterEgo | capitalizefirst }}
- </a>
- </mat-option>
-</mat-autocomplete>
-
-
- ./search-bar.component.scss
-
@import '../../../../styles/mixins';
-@import '../../../../styles/colors';
-
-.hero-link {
- text-decoration: none;
-}
-
- -
- src/app/modules/auth/pages/sign-up-page/sign-up-page.component.ts
-
| selector | -app-sign-up-page |
-
| styleUrls | -./sign-up-page.component.scss |
-
| templateUrl | -./sign-up-page.component.html |
-
- Properties- |
-
| - - | -
- Methods- |
-
-
|
-
-constructor(formBuilder: FormBuilder, authService: AuthService, router: Router, utilsService: UtilsService)
- |
- |||||||||||||||
| - - | -|||||||||||||||
|
-
- Parameters :
-
-
|
-
| - - - getErrorMessage - - - | -||||||
-getErrorMessage(field: any)
- |
- ||||||
| - - | -||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- string | void
-
-
-
-
- |
-
| - - - sendForm - - - | -
-sendForm()
- |
-
| - - | -
|
-
-
- Returns :
- void
-
- |
-
| - - - email - - - | -
- Default value : new FormControl('', [Validators.required, Validators.email])
- |
-
| - - | -
| - - - firstName - - - | -
- Default value : new FormControl('', [Validators.required, Validators.maxLength(100)])
- |
-
| - - | -
| - - - hide - - - | -
- Default value : true
- |
-
| - - | -
| - - - lastName - - - | -
- Default value : new FormControl('', [Validators.required, Validators.maxLength(100)])
- |
-
| - - | -
| - - - password - - - | -
- Default value : new FormControl('', [
- Validators.required,
- Validators.pattern('^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]{8,}$'),
- ])
- |
-
| - - | -
| - - - signUpForm - - - | -
- Type : FormGroup
-
- |
-
| - - | -
import { Component } from '@angular/core';
-import { transition, trigger, useAnimation } from '@angular/animations';
-import { fadeIn } from 'ng-animate';
-import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
-import { AuthService } from '../../auth.service';
-import { UtilsService } from '../../../../shared/services/utils.service';
-import { RoutesConfig } from '../../../../configs/routes.config';
-import { Router } from '@angular/router';
-
-@Component({
- selector: 'app-sign-up-page',
- templateUrl: './sign-up-page.component.html',
- styleUrls: ['./sign-up-page.component.scss'],
- animations: [
- trigger('fadeIn', [
- transition(
- '* => *',
- useAnimation(fadeIn, {
- params: { timing: 1, delay: 0 },
- })
- ),
- ]),
- ],
-})
-export class SignUpPageComponent {
- signUpForm: FormGroup;
- firstName = new FormControl('', [Validators.required, Validators.maxLength(100)]);
- lastName = new FormControl('', [Validators.required, Validators.maxLength(100)]);
- email = new FormControl('', [Validators.required, Validators.email]);
- password = new FormControl('', [
- Validators.required,
- Validators.pattern('^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]{8,}$'),
- ]);
- hide = true;
-
- constructor(
- private formBuilder: FormBuilder,
- private authService: AuthService,
- private router: Router,
- private utilsService: UtilsService
- ) {
- this.signUpForm = this.formBuilder.group({
- firstName: this.firstName,
- lastName: this.lastName,
- email: this.email,
- password: this.password,
- });
- }
-
- getErrorMessage(field: any): string | void {
- // @ts-ignore
- const classField: any = this[field];
- if (classField?.hasError('required')) {
- return 'You must enter a value';
- } else if (classField?.hasError('email')) {
- return 'Not a valid email';
- } else if (classField?.hasError('pattern')) {
- return 'Not a valid password';
- }
- }
-
- sendForm() {
- if (this.signUpForm.valid) {
- const formValue = this.signUpForm.value;
- this.authService
- .signUp(formValue.firstName, formValue.lastName, formValue.email, formValue.password)
- .subscribe((response: any) => {
- if (!response.errors) {
- this.router.navigate([RoutesConfig.routes.auth.logIn]).then(() => {
- this.utilsService.showSnackBar('Cool! Now try to log in!', 'info-snack-bar');
- });
- } else if (response.errors[0].code === 10000) {
- this.utilsService.showSnackBar(
- 'This email is not available. Try again, with a different one.',
- 'warning-snack-bar'
- );
- }
- });
- }
- }
-}
-
- <mat-grid-list cols="1" rows="1" rowHeight="2:1">
- <mat-grid-tile>
- <mat-card class="signup--form__box--blue">
- <div class="signup--form-container">
- <p class="signup--form__header-title">Give it a try!</p>
- <form class="example-container" [formGroup]="signUpForm">
- <p>
- <mat-form-field appearance="outline">
- <mat-label>First name</mat-label>
- <input [formControl]="firstName" matInput placeholder="Jason" />
- <mat-icon matSuffix>sentiment_very_satisfied</mat-icon>
- <mat-error *ngIf="email.invalid">{{ getErrorMessage('firstName') }}</mat-error>
- </mat-form-field>
- </p>
- <p>
- <mat-form-field appearance="outline">
- <mat-label>Last name</mat-label>
- <input [formControl]="lastName" matInput placeholder="Bourne" />
- <mat-icon matSuffix>favorite</mat-icon>
- <mat-error *ngIf="email.invalid">{{ getErrorMessage('lastName') }}</mat-error>
- </mat-form-field>
- </p>
- <p>
- <mat-form-field appearance="outline">
- <mat-label>Enter your email</mat-label>
- <input matInput placeholder="pat@example.com" [formControl]="email" required />
- <mat-error *ngIf="email.invalid">{{ getErrorMessage('email') }}</mat-error>
- </mat-form-field>
- </p>
- <p>
- <mat-form-field appearance="outline">
- <mat-label>Enter a password</mat-label>
- <input matInput [formControl]="password" [type]="hide ? 'password' : 'text'" />
- <button
- mat-icon-button
- matSuffix
- (click)="hide = !hide"
- [attr.aria-label]="'Hide password'"
- [attr.aria-pressed]="hide"
- >
- <mat-icon>{{ hide ? 'visibility_off' : 'visibility' }}</mat-icon>
- </button>
- <mat-hint
- >Must be minimum eight characters, at least one uppercase letter, one lowercase
- letter and one number</mat-hint
- >
- <mat-error *ngIf="password.invalid">{{ getErrorMessage('password') }}</mat-error>
- </mat-form-field>
- </p>
- <p>
- <button
- class="signup--form__submit-button"
- mat-raised-button
- color="primary"
- (click)="sendForm()"
- >
- {{ 'Sign Up' | uppercase }}
- </button>
- </p>
- </form>
- </div>
- </mat-card>
- </mat-grid-tile>
-</mat-grid-list>
-
-
- ./sign-up-page.component.scss
-
@import '../../../../styles/mixins';
-
-.signup--form-container {
- text-align: center;
-
- p {
- margin-bottom: 1rem;
- }
-
- .signup--form__header-title {
- margin-bottom: 2rem;
- }
-}
-
-.signup--form-container .mat-form-field + .mat-form-field {
- margin-left: 8px;
-}
-
-.mat-form-field {
- width: 100%;
-}
-
-.signup--form__box--blue {
- padding: 4rem;
-}
-
-:host ::ng-deep .mat-form-field-flex {
- background: rgb(245, 245, 245);
-}
-
-.signup--form__header-title {
- font-weight: bold;
- font-size: 20px;
- color: #000000de;
-}
-
-.signup--form__submit-button {
- margin-top: 40px;
-}
-
- -
- src/app/shared/components/spinner/spinner.component.ts
-
| selector | -app-spinner |
-
| styleUrls | -./spinner.component.scss |
-
| templateUrl | -./spinner.component.html |
-
-constructor()
- |
-
| - - | -
import { Component } from '@angular/core';
-
-@Component({
- selector: 'app-spinner',
- templateUrl: './spinner.component.html',
- styleUrls: ['./spinner.component.scss'],
-})
-export class SpinnerComponent {
- constructor() {}
-}
-
- <div class="spinner"></div>
-
-
- ./spinner.component.scss
-
.spinner {
- width: 40px;
- height: 40px;
- background-color: #333;
-
- border-radius: 100%;
- -webkit-animation: sk-scaleout 1s infinite ease-in-out;
- animation: sk-scaleout 1s infinite ease-in-out;
-
- transform: translate(-50%, -50%);
- position: absolute;
- left: 50%;
- top: 48%;
-}
-
-@-webkit-keyframes sk-scaleout {
- 0% {
- -webkit-transform: scale(0);
- }
- 100% {
- -webkit-transform: scale(1);
- opacity: 0;
- }
-}
-
-@keyframes sk-scaleout {
- 0% {
- -webkit-transform: scale(0);
- transform: scale(0);
- }
- 100% {
- -webkit-transform: scale(1);
- transform: scale(1);
- opacity: 0;
- }
-}
-
- | File | -Type | -Identifier | -Statements | -
|---|---|---|---|
| - - src/app/app.component.ts - | -component | -AppComponent | -- 0 % - (0/7) - | -
| - - src/app/app.component.ts - | -variable | -Modernizr | -- 0 % - (0/1) - | -
| - - src/app/configs/app.config.ts - | -variable | -APP_CONFIG | -- 0 % - (0/1) - | -
| - - src/app/configs/app.config.ts - | -variable | -AppConfig | -- 0 % - (0/1) - | -
| - - src/app/configs/endpoints.config.ts - | -variable | -ENDPOINTS_CONFIG | -- 0 % - (0/1) - | -
| - - src/app/configs/endpoints.config.ts - | -variable | -EndpointsConfig | -- 0 % - (0/1) - | -
| - - src/app/configs/routes.config.ts - | -variable | -basePaths | -- 0 % - (0/1) - | -
| - - src/app/configs/routes.config.ts - | -variable | -getHeroDetail | -- 0 % - (0/1) - | -
| - - src/app/configs/routes.config.ts - | -variable | -ROUTES_CONFIG | -- 0 % - (0/1) - | -
| - - src/app/configs/routes.config.ts - | -variable | -RoutesConfig | -- 0 % - (0/1) - | -
| - - src/app/configs/routes.config.ts - | -variable | -routesNames | -- 0 % - (0/1) - | -
| - - src/app/modules/auth/auth-routing.module.ts - | -variable | -authRoutes | -- 0 % - (0/1) - | -
| - - src/app/modules/auth/auth.guard.ts - | -guard | -AuthGuard | -- 0 % - (0/3) - | -
| - - src/app/modules/auth/auth.service.ts - | -injectable | -AuthService | -- 0 % - (0/5) - | -
| - - src/app/modules/auth/pages/log-in-page/log-in-page.component.ts - | -component | -LogInPageComponent | -- 0 % - (0/9) - | -
| - - src/app/modules/auth/pages/sign-up-page/sign-up-page.component.ts - | -component | -SignUpPageComponent | -- 0 % - (0/10) - | -
| - - src/app/modules/core/interceptors/timing.interceptor.ts - | -interceptor | -TimingInterceptor | -- 0 % - (0/3) - | -
| - - src/app/modules/core/interceptors/token.interceptor.ts - | -interceptor | -TokenInterceptor | -- 33 % - (1/3) - | -
| - - src/app/modules/core/sentry.errorhandler.ts - | -injectable | -SentryErrorHandler | -- 0 % - (0/3) - | -
| - - src/app/modules/core/services/events.servide.ts - | -injectable | -EventsService | -- 0 % - (0/4) - | -
| - - src/app/modules/core/services/events.servide.ts - | -interface | -EventType | -- 0 % - (0/5) - | -
| - - src/app/modules/core/services/logger.service.ts - | -injectable | -LoggerService | -- 0 % - (0/3) - | -
| - - src/app/modules/core/services/utils-helper.service.ts - | -injectable | -UtilsHelperService | -- 0 % - (0/3) - | -
| - - src/app/modules/core/services/utils-helper.service.ts - | -variable | -bowser | -- 0 % - (0/1) - | -
| - - src/app/modules/core/services/utils-helper.service.ts - | -variable | -require | -- 0 % - (0/1) - | -
| - - src/app/modules/hero/components/hero-remove/hero-remove.component.ts - | -component | -HeroRemoveComponent | -- 0 % - (0/2) - | -
| - - src/app/modules/hero/hero-routing.module.ts - | -variable | -heroRoutes | -- 0 % - (0/1) - | -
| - - src/app/modules/hero/pages/hero-detail-page/hero-detail-page.component.ts - | -component | -HeroDetailPageComponent | -- 0 % - (0/6) - | -
| - - src/app/modules/hero/pages/my-heroes-page/my-heroes-page.component.ts - | -component | -MyHeroesPageComponent | -- 0 % - (0/15) - | -
| - - src/app/modules/hero/shared/hero.model.ts - | -class | -Hero | -- 0 % - (0/9) - | -
| - - src/app/modules/hero/shared/hero.resolver.ts - | -guard | -HeroResolver | -- 0 % - (0/3) - | -
| - - src/app/modules/hero/shared/hero.service.ts - | -injectable | -HeroService | -- 0 % - (0/7) - | -
| - - src/app/modules/root/pages/error404-page/error404-page.component.ts - | -component | -Error404PageComponent | -- 0 % - (0/2) - | -
| - - src/app/modules/root/pages/home-page/home-page.component.ts - | -component | -HomePageComponent | -- 0 % - (0/4) - | -
| - - src/app/modules/root/root-routing.module.ts - | -variable | -routesNames | -- 0 % - (0/1) - | -
| - - src/app/modules/root/shared/footer/footer.component.ts - | -component | -FooterComponent | -- 0 % - (0/2) - | -
| - - src/app/modules/root/shared/header/header.component.ts - | -component | -HeaderComponent | -- 0 % - (0/11) - | -
| - - src/app/modules/root/shared/search-bar/search-bar.component.ts - | -component | -SearchBarComponent | -- 0 % - (0/8) - | -
| - - src/app/modules/user/shared/user.model.ts - | -class | -User | -- 0 % - (0/9) - | -
| - - src/app/modules/user/user.service.ts - | -injectable | -UserService | -- 0 % - (0/3) - | -
| - - src/app/shared/components/hero-card/hero-card.component.ts - | -component | -HeroCardComponent | -- 0 % - (0/5) - | -
| - - src/app/shared/components/hero-loading/hero-loading.component.ts - | -component | -HeroLoadingComponent | -- 0 % - (0/2) - | -
| - - src/app/shared/components/loading-placeholder/loading-placeholder.component.ts - | -component | -LoadingPlaceholderComponent | -- 0 % - (0/4) - | -
| - - src/app/shared/components/spinner/spinner.component.ts - | -component | -SpinnerComponent | -- 0 % - (0/2) - | -
| - - src/app/shared/interfaces/deserializable.interface.ts - | -interface | -Deserializable | -- 0 % - (0/2) - | -
| - - src/app/shared/modules/graphql.module.ts - | -function | -createApollo | -- 0 % - (0/1) - | -
| - - src/app/shared/pipes/capitalize-first.pipe.ts - | -pipe | -CapitalizeFirstPipe | -- 0 % - (0/1) - | -
| - - src/app/shared/services/storage.service.ts - | -injectable | -StorageService | -- 0 % - (0/5) - | -
| - - src/app/shared/services/utils.service.ts - | -injectable | -UtilsService | -- 0 % - (0/3) - | -
| - - src/environments/environment.prod.ts - | -variable | -environment | -- 0 % - (0/1) - | -
| - - src/environments/environment.ts - | -variable | -environment | -- 0 % - (0/1) - | -
| - - src/test.ts - | -variable | -context | -- 0 % - (0/1) - | -
| - - src/test.ts - | -variable | -require | -- 0 % - (0/1) - | -
-
- src/app/modules/auth/auth.guard.ts
-
- Methods- |
-
-
|
-
-constructor(authService: AuthService, router: Router)
- |
- |||||||||
|
- Defined in src/app/modules/auth/auth.guard.ts:7
- |
- |||||||||
|
-
- Parameters :
-
-
|
-
| - - - canActivate - - - | -|||||||||
-canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot)
- |
- |||||||||
|
- Defined in src/app/modules/auth/auth.guard.ts:10
- |
- |||||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- Promise<boolean>
-
-
-
-
- |
-
import { Injectable } from '@angular/core';
-import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
-import { AuthService } from './auth.service';
-import { RoutesConfig } from '../../configs/routes.config';
-
-@Injectable()
-export class AuthGuard implements CanActivate {
- constructor(private authService: AuthService, private router: Router) {}
-
- canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
- return new Promise(resolve => {
- if (this.authService.isLoggedIn()) {
- resolve(true);
- } else {
- this.router.navigate([RoutesConfig.routes.home]);
- resolve(false);
- }
- });
- }
-}
-
- -
- src/app/modules/hero/shared/hero.resolver.ts
-
- Methods- |
-
-
|
-
-constructor(heroService: HeroService)
- |
- ||||||
| - - | -||||||
|
-
- Parameters :
-
-
|
-
| - - - Async - resolve - - - | -||||||
-
- resolve(route: ActivatedRouteSnapshot)
- |
- ||||||
| - - | -||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- unknown
-
-
-
-
- |
-
import { Injectable } from '@angular/core';
-import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
-import { Hero } from './hero.model';
-import { Observable } from 'rxjs';
-import { HeroService } from './hero.service';
-
-@Injectable()
-export class HeroResolver implements Resolve<Observable<Hero>> {
- constructor(private heroService: HeroService) {}
-
- async resolve(route: ActivatedRouteSnapshot) {
- const id: string = route.paramMap.get('id') || '';
- return this.heroService.getHeroById(id);
- }
-}
-
- -
- Example app with Angular 13 + Angular CLI + i18n + Graphql
-
-
- :clap::clap::tada::tada::tada::tada::clap::clap:
-
-
- Base project made with much :heart:. Contains CRUD, advanced patterns, generated library, and much more!
-
-
-
-
-
- DEMO HERE
-
npm i
-npm startThis project is using a real app deployed in heroku, which you can see -here. The server is using NesjJS, Prisma, -Postgres and GraphQL. Please check it out and feel free also to contribute or give me your thoughts.
-This project is using the official internationalization. You can navigate through every language If -you want to translate the messages you can use this awesome tool, -Tiny Translator.
-Have a bug or a feature request? Please first read the issue guidelines and search for existing and -closed issues. If your problem or idea is not addressed yet, -please open a new issue.
-Ismael Ramos
- -Thanks to all contributors and their support.
-If you have an idea or you want to do something, tell me or just do it! I'm always happy to hear -your feedback!
-Code and documentation copyright 2021 the authors. Code released under the -MIT License.
-Enjoy :metal:
- - - - - - - - - - - - - - - - - - - - - --
- src/app/modules/auth/auth.service.ts
-
- Methods- |
-
-
|
-
-constructor(snackBar: MatSnackBar, apollo: Apollo, utilsService: UtilsService, storageService: StorageService)
- |
- |||||||||||||||
|
- Defined in src/app/modules/auth/auth.service.ts:13
- |
- |||||||||||||||
|
-
- Parameters :
-
-
|
-
| - - - isLoggedIn - - - | -
-isLoggedIn()
- |
-
|
- Defined in src/app/modules/auth/auth.service.ts:21
- |
-
|
-
-
- Returns :
- boolean
-
- |
-
| - - - logIn - - - | -|||||||||
-logIn(email: string, password: string)
- |
- |||||||||
|
- Defined in src/app/modules/auth/auth.service.ts:62
- |
- |||||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- Observable<literal type>
-
-
-
-
- |
-
| - - - signUp - - - | -|||||||||||||||
-signUp(firstName: string, lastName: string, email: string, password: string)
- |
- |||||||||||||||
|
- Defined in src/app/modules/auth/auth.service.ts:33
- |
- |||||||||||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- Observable<literal type>
-
-
-
-
- |
-
import { Observable } from 'rxjs';
-import { Injectable } from '@angular/core';
-import { MatSnackBar } from '@angular/material/snack-bar';
-import { Apollo, gql } from 'apollo-angular';
-import { map } from 'rxjs/operators';
-import { UtilsService } from '~shared/services/utils.service';
-import jwt_decode from 'jwt-decode';
-import { StorageService } from '~shared/services/storage.service';
-
-@Injectable({
- providedIn: 'root',
-})
-export class AuthService {
- constructor(
- private snackBar: MatSnackBar,
- private apollo: Apollo,
- private utilsService: UtilsService,
- private storageService: StorageService
- ) {}
-
- isLoggedIn(): boolean {
- try {
- const token = this.storageService.getCookie('accessToken');
- if (token) {
- return !!jwt_decode(token);
- }
- return false;
- } catch (Error) {
- return false;
- }
- }
-
- signUp(
- firstName: string,
- lastName: string,
- email: string,
- password: string
- ): Observable<{ accessToken: string; refreshToken: string }> {
- return this.apollo
- .mutate({
- mutation: gql`
- mutation signUp {
- signup(data: {
- email: "${email}"
- firstname: "${firstName}"
- lastname: "${lastName}"
- password: "${password}"
- }) {
- accessToken
- refreshToken
- }
- }
- `,
- })
- .pipe(
- map((response: any) => {
- return !response.errors ? response.data.signup : response;
- })
- );
- }
-
- logIn(
- email: string,
- password: string
- ): Observable<{ accessToken: string; refreshToken: string }> {
- return this.apollo
- .mutate({
- mutation: gql`
- mutation logIn {
- login(data: {
- email: "${email}"
- password: "${password}"
- }) {
- accessToken
- refreshToken
- }
- }
- `,
- })
- .pipe(
- map((response: any) => {
- if (!response.errors) {
- const loginData = response.data.login;
- const { accessToken, refreshToken } = loginData;
- this.storageService.setCookie('accessToken', accessToken);
- this.storageService.setCookie('refreshToken', refreshToken);
- this.utilsService.showSnackBar("Nice! Let's create some heroes", 'info-snack-bar');
- return loginData;
- } else {
- return response;
- }
- })
- );
- }
-}
-
- -
- src/app/modules/core/services/events.servide.ts
-
- Properties- |
-
-
|
-
- Methods- |
-
-
|
-
-constructor()
- |
-
| - - | -
| - - - Public - send - - - | -||||||
-
- send(opts: literal type)
- |
- ||||||
| - - | -||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- void
-
-
-
-
- |
-
| - - - Public - events$ - - - | -
- Type : EventEmitter<EventType>
-
- |
-
| - - | -
import { EventEmitter, Injectable } from '@angular/core';
-import { v1 as uuidv1 } from 'uuid';
-
-export enum EventsTypes {
- UPDATE_HEROES = 'UPDATE_HEROES',
-}
-
-export default interface EventType {
- id: string;
- date: Date;
- type: string;
- data?: any;
-}
-
-@Injectable({
- providedIn: 'root',
-})
-export class EventsService {
- public events$: EventEmitter<EventType>;
-
- constructor() {
- this.events$ = new EventEmitter();
- }
-
- public send(opts: { data?: any; type: string }): void {
- const event: EventType = {
- date: new Date(),
- id: uuidv1(),
- data: opts.data,
- type: opts.type,
- };
-
- this.events$.emit(event);
- }
-}
-
- -
- src/app/modules/hero/shared/hero.service.ts
-
- Methods- |
-
-
|
-
-constructor(apollo: Apollo)
- |
- ||||||
| - - | -||||||
|
-
- Parameters :
-
-
|
-
| - - - createHero - - - | -||||||
-createHero(hero: Hero)
- |
- ||||||
| - - | -||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- any
-
-
-
-
- |
-
| - - - getHeroById - - - | -||||||
-getHeroById(id: string)
- |
- ||||||
| - - | -||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- Observable<Hero>
-
-
-
-
- |
-
| - - - removeHero - - - | -||||||
-removeHero(id: string)
- |
- ||||||
| - - | -||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- any
-
-
-
-
- |
-
| - - - searchHeroes - - - | -|||||
-searchHeroes(undefined: literal type)
- |
- |||||
| - - | -|||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- Observable<Hero[]>
-
-
-
-
- |
-
| - - - voteHero - - - | -||||||
-voteHero(hero: Hero)
- |
- ||||||
| - - | -||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- any
-
-
-
-
- |
-
import { Observable } from 'rxjs';
-import { Injectable } from '@angular/core';
-import { map } from 'rxjs/operators';
-import { Hero } from './hero.model';
-import { Apollo, gql } from 'apollo-angular';
-import { WatchQueryFetchPolicy } from '@apollo/client/core';
-
-@Injectable({
- providedIn: 'root',
-})
-export class HeroService {
- constructor(private apollo: Apollo) {}
-
- searchHeroes({ fetchPolicy }: { fetchPolicy: WatchQueryFetchPolicy }): Observable<Hero[]> {
- return this.apollo
- .watchQuery({
- query: gql`
- query GetFeed {
- searchHeroes(
- query: ""
- after: ""
- first: 10
- orderBy: { direction: desc, field: usersVoted }
- skip: 0
- ) {
- edges {
- cursor
- node {
- id
- realName
- alterEgo
- image
- published
- usersVoted {
- firstname
- }
- }
- }
- pageInfo {
- endCursor
- hasNextPage
- hasPreviousPage
- startCursor
- }
- totalCount
- }
- }
- `,
- fetchPolicy,
- })
- .valueChanges.pipe(
- map((result: any) => result.data.searchHeroes.edges.map((edge: any) => new Hero(edge.node)))
- );
- }
-
- getHeroById(id: string): Observable<Hero> {
- return this.apollo
- .watchQuery({
- query: gql`
- query Hero {
- hero(heroId: "${id}") {
- id
- realName
- alterEgo
- image
- published
- }
- }
- `,
- })
- .valueChanges.pipe(map((result: any) => new Hero(result.data.hero)));
- }
-
- createHero(hero: Hero) {
- return this.apollo
- .mutate({
- mutation: gql`
- mutation CreateHero {
- createHero(data: {
- realName: "${hero.realName}"
- alterEgo: "${hero.alterEgo}"
- }) {
- id
- realName
- alterEgo
- image
- published
- }
- }
- `,
- })
- .pipe(
- map((response: any) => {
- return !response.errors ? response.data.createHero : response;
- })
- );
- }
-
- voteHero(hero: Hero) {
- return this.apollo
- .mutate({
- mutation: gql`
- mutation VoteHero {
- voteHero(heroId: "${hero.id}") {
- id
- }
- }
- `,
- })
- .pipe(
- map((response: any) => {
- return !response.errors ? response.data.voteHero : response;
- })
- );
- }
-
- removeHero(id: string) {
- return this.apollo
- .mutate({
- mutation: gql`
- mutation RemoveHero {
- removeHero(heroId: "${id}") {
- id
- }
- }
- `,
- })
- .pipe(
- map((response: any) => {
- return !response.errors ? {} : response;
- })
- );
- }
-}
-
- -
- src/app/modules/core/services/logger.service.ts
-
- Methods- |
-
| - - | -
| - - - Static - error - - - | -||||||||||||
-
- error(msg: string, obj: object)
- |
- ||||||||||||
| - - | -||||||||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- void
-
-
-
-
- |
-
| - - - Static - log - - - | -||||||
-
- log(msg: string)
- |
- ||||||
| - - | -||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- void
-
-
-
-
- |
-
import { Injectable } from '@angular/core';
-
-@Injectable({
- providedIn: 'root',
-})
-export class LoggerService {
- static log(msg: string): void {
- console.log(msg);
- }
-
- static error(msg: string, obj = {}): void {
- console.error(msg, obj);
- }
-}
-
- -
- src/app/modules/core/sentry.errorhandler.ts
-
- Methods- |
-
-
|
-
-constructor()
- |
-
| - - | -
| - - - handleError - - - | -||||||
-handleError(error: any)
- |
- ||||||
| - - | -||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- void
-
-
-
-
- |
-
import * as Sentry from '@sentry/browser';
-import { ErrorHandler, Injectable } from '@angular/core';
-import { AppConfig } from '~app/configs/app.config';
-
-Sentry.init({
- dsn: AppConfig.sentryDSN,
-});
-
-@Injectable()
-export class SentryErrorHandler implements ErrorHandler {
- constructor() {}
-
- handleError(error: any) {
- Sentry.captureException(error.originalError || error);
- throw error;
- }
-}
-
- -
- src/app/shared/services/storage.service.ts
-
- Methods- |
-
-
|
-
-constructor()
- |
-
|
- Defined in src/app/shared/services/storage.service.ts:7
- |
-
| - - - getCookie - - - | -||||||
-getCookie(name: string)
- |
- ||||||
| - - | -||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- string | undefined
-
-
-
-
- |
-
| - - - removeCookie - - - | -||||||
-removeCookie(name: string)
- |
- ||||||
| - - | -||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- void
-
-
-
-
- |
-
| - - - setCookie - - - | -||||||||||||
-setCookie(name: string, value: string, expires?: number)
- |
- ||||||||||||
| - - | -||||||||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- string | undefined
-
-
-
-
- |
-
import { Injectable } from '@angular/core';
-import Cookies from 'js-cookie';
-
-@Injectable({
- providedIn: 'root',
-})
-export class StorageService {
- constructor() {}
-
- getCookie(name: string): string | undefined {
- return Cookies.get(name);
- }
-
- setCookie(name: string, value: string, expires?: number): string | undefined {
- return Cookies.set(name, value, { expires: expires || 365 });
- }
-
- removeCookie(name: string): void {
- return Cookies.remove(name);
- }
-}
-
- -
- src/app/modules/user/user.service.ts
-
- Methods- |
-
-
|
-
-constructor(apollo: Apollo)
- |
- ||||||
|
- Defined in src/app/modules/user/user.service.ts:11
- |
- ||||||
|
-
- Parameters :
-
-
|
-
| - - - getMe - - - | -|||||
-getMe(undefined: literal type)
- |
- |||||
|
- Defined in src/app/modules/user/user.service.ts:14
- |
- |||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- Observable<User>
-
-
-
-
- |
-
import { Observable } from 'rxjs';
-import { Injectable } from '@angular/core';
-import { Apollo, gql } from 'apollo-angular';
-import { map } from 'rxjs/operators';
-import { User } from './shared/user.model';
-import { WatchQueryFetchPolicy } from '@apollo/client/core';
-
-@Injectable({
- providedIn: 'root',
-})
-export class UserService {
- constructor(private apollo: Apollo) {}
-
- getMe({ fetchPolicy }: { fetchPolicy: WatchQueryFetchPolicy }): Observable<User> {
- return this.apollo
- .watchQuery({
- query: gql`
- query Me {
- me {
- id
- email
- firstname
- lastname
- heroes {
- id
- realName
- alterEgo
- }
- }
- }
- `,
- fetchPolicy,
- })
- .valueChanges.pipe(map((result: any) => new User(result.data.me)));
- }
-}
-
- -
- src/app/modules/core/services/utils-helper.service.ts
-
- Methods- |
-
-
|
-
| - - - Static - isBrowserValid - - - | -
-
- isBrowserValid()
- |
-
| - - | -
|
-
-
- Returns :
- any
-
- |
-
| - - - Static - isPalindrome - - - | -||||||
-
- isPalindrome(str: string)
- |
- ||||||
| - - | -||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- boolean
-
-
-
-
- |
-
import { Injectable } from '@angular/core';
-
-declare const require: any;
-const bowser = require('bowser');
-
-@Injectable({
- providedIn: 'root',
-})
-export class UtilsHelperService {
- static isPalindrome(str: string) {
- const len = Math.floor(str.length / 2);
- for (let i = 0; i < len; i++) {
- if (str[i] !== str[str.length - i - 1]) {
- return false;
- }
- }
- return true;
- }
-
- static isBrowserValid() {
- const browser = bowser.getParser(window.navigator.userAgent);
- return browser.satisfies({
- windows: {
- 'internet explorer': '>10',
- },
- macos: {
- safari: '>10.1',
- },
- chrome: '>20.1.1432',
- firefox: '>31',
- opera: '>22',
- });
- }
-}
-
- -
- src/app/shared/services/utils.service.ts
-
- Methods- |
-
-
|
-
-constructor(snackBar: MatSnackBar)
- |
- ||||||
|
- Defined in src/app/shared/services/utils.service.ts:8
- |
- ||||||
|
-
- Parameters :
-
-
|
-
| - - - showSnackBar - - - | -|||||||||
-showSnackBar(name: string, panelClass: string)
- |
- |||||||||
|
- Defined in src/app/shared/services/utils.service.ts:11
- |
- |||||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- void
-
-
-
-
- |
-
import { Injectable } from '@angular/core';
-import { MatSnackBar, MatSnackBarConfig } from '@angular/material/snack-bar';
-import { AppConfig } from '~app/configs/app.config';
-
-@Injectable({
- providedIn: 'root',
-})
-export class UtilsService {
- constructor(private snackBar: MatSnackBar) {}
-
- showSnackBar(name: string, panelClass: string): void {
- const config: any = new MatSnackBarConfig();
- config.duration = panelClass === 'warning-snack-bar' ? 50000 : AppConfig.snackBarDuration;
- config.horizontalPosition = 'right';
- config.verticalPosition = 'top';
- config.panelClass = panelClass;
- this.snackBar.open(name, 'OK', config);
- }
-}
-
- -
- src/app/modules/core/interceptors/timing.interceptor.ts
-
- Methods- |
-
-
|
-
-constructor()
- |
-
| - - | -
| - - - intercept - - - | -|||||||||
-intercept(req: HttpRequest
- |
- |||||||||
| - - | -|||||||||
|
-
-
- Parameters :
-
-
-
-
-
- Returns :
- Observable<HttpEvent<any>>
-
-
-
-
- |
-
import { tap } from 'rxjs/operators';
-import {
- HttpEvent,
- HttpHandler,
- HttpInterceptor,
- HttpRequest,
- HttpResponse,
-} from '@angular/common/http';
-import { Observable } from 'rxjs';
-import { LoggerService } from '../services/logger.service';
-import { Injectable } from '@angular/core';
-
-@Injectable()
-export class TimingInterceptor implements HttpInterceptor {
- constructor() {}
-
- intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
- const started = Date.now();
- return next.handle(req).pipe(
- tap(event => {
- if (event instanceof HttpResponse) {
- const elapsed = Date.now() - started;
- LoggerService.log(`Request for ${req.urlWithParams} took ${elapsed} ms.`);
- }
- })
- );
- }
-}
-
- -
- src/app/modules/core/interceptors/token.interceptor.ts
-
- Methods- |
-
-
|
-
-constructor(storageService: StorageService)
- |
- ||||||
| - - | -||||||
|
-
- Parameters :
-
-
|
-
| - - - intercept - - - | -||||||||||||
-intercept(request: HttpRequest
- |
- ||||||||||||
| - - | -||||||||||||
-
- Parameters :
-
-
-
-
-
- Returns :
- Observable<HttpEvent<any>>
-
-
-
- An Observable with the request modified - - |
-
import { Observable, throwError as observableThrowError } from 'rxjs';
-import { catchError } from 'rxjs/operators';
-import { Injectable } from '@angular/core';
-import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
-import { v4 as uuid4 } from 'uuid';
-import { StorageService } from '~shared/services/storage.service';
-
-@Injectable()
-export class TokenInterceptor implements HttpInterceptor {
- constructor(private storageService: StorageService) {}
-
- /**
- * @param request The initial request
- * @param next The http handler
- * @returns An Observable with the request modified
- */
- /**
- * @example
- * intercept(request, next)
- */
- intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
- const headers = { req_uuid: uuid4(), Authorization: '' };
-
- const token = this.storageService.getCookie('accessToken');
-
- if (token && !request.headers.get('bypassAuthorization')) {
- headers['Authorization'] = `Bearer ${token}`;
- }
-
- const newRequest = request.clone({
- setHeaders: headers,
- });
-
- return next.handle(newRequest).pipe(catchError(err => observableThrowError(err)));
- }
-}
-
- -
- src/app/shared/interfaces/deserializable.interface.ts
-
- Methods- |
-
-
|
-
| - - - deserialize - - - | -||||||
-deserialize(input: any)
- |
- ||||||
| - - | -||||||
|
-
-
- Parameters :
-
-
-
-
- |
-
export interface Deserializable {
- deserialize(input: any): this;
-}
-
- -
- src/app/modules/core/services/events.servide.ts
-
- Properties- |
-
| - - | -
| - - data - - - - - | -
- data:
- |
-
- Type : any
-
- |
-
| - Optional - | -
| - - date - - - - - | -
- date:
- |
-
- Type : Date
-
- |
-
| - - id - - - - - | -
- id:
- |
-
- Type : string
-
- |
-
| - - type - - - - - | -
- type:
- |
-
- Type : string
-
- |
-
import { EventEmitter, Injectable } from '@angular/core';
-import { v1 as uuidv1 } from 'uuid';
-
-export enum EventsTypes {
- UPDATE_HEROES = 'UPDATE_HEROES',
-}
-
-export default interface EventType {
- id: string;
- date: Date;
- type: string;
- data?: any;
-}
-
-@Injectable({
- providedIn: 'root',
-})
-export class EventsService {
- public events$: EventEmitter<EventType>;
-
- constructor() {
- this.events$ = new EventEmitter();
- }
-
- public send(opts: { data?: any; type: string }): void {
- const event: EventType = {
- date: new Date(),
- id: uuidv1(),
- data: opts.data,
- type: opts.type,
- };
-
- this.events$.emit(event);
- }
-}
-
-