├── LICENSE
├── README.md
├── ch1
└── angular-start
│ ├── .editorconfig
│ ├── .gitignore
│ ├── .vscode
│ ├── extensions.json
│ ├── launch.json
│ └── tasks.json
│ ├── README.md
│ ├── angular.json
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ ├── app
│ │ ├── about
│ │ │ ├── about.component.css
│ │ │ ├── about.component.html
│ │ │ ├── about.component.spec.ts
│ │ │ └── about.component.ts
│ │ ├── app-routing.module.ts
│ │ ├── app.component.css
│ │ ├── app.component.html
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── app.module.ts
│ │ └── home
│ │ │ ├── home.component.css
│ │ │ ├── home.component.html
│ │ │ ├── home.component.spec.ts
│ │ │ └── home.component.ts
│ ├── assets
│ │ └── .gitkeep
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ └── styles.css
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ └── tsconfig.spec.json
├── ch10
├── gym-diary-backend
│ ├── .eslintrc.js
│ ├── .gitignore
│ ├── .prettierrc
│ ├── README.md
│ ├── nest-cli.json
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── app.controller.spec.ts
│ │ ├── app.controller.ts
│ │ ├── app.module.ts
│ │ ├── app.service.ts
│ │ ├── auth
│ │ │ ├── auth.controller.ts
│ │ │ ├── auth.guard.ts
│ │ │ ├── auth.module.ts
│ │ │ ├── auth.service.spec.ts
│ │ │ ├── auth.service.ts
│ │ │ ├── constants.ts
│ │ │ └── public.decorator.ts
│ │ ├── diary
│ │ │ ├── db
│ │ │ │ └── diary.data.ts
│ │ │ ├── diary.controller.ts
│ │ │ ├── diary.module.ts
│ │ │ ├── dto
│ │ │ │ ├── create-diaries.dto.ts
│ │ │ │ └── get-diaries.dto.ts
│ │ │ ├── exercises.service.ts
│ │ │ ├── interface
│ │ │ │ └── diary.interface.ts
│ │ │ └── repository
│ │ │ │ ├── diary-repository-memory.service.ts
│ │ │ │ └── diary-repository.service.ts
│ │ ├── exercises
│ │ │ ├── db
│ │ │ │ └── exercises.data.ts
│ │ │ ├── dto
│ │ │ │ ├── create-exercises.dto.ts
│ │ │ │ └── get-exercises.dto.ts
│ │ │ ├── exercises.controller.ts
│ │ │ ├── exercises.module.ts
│ │ │ ├── exercises.service.ts
│ │ │ ├── interface
│ │ │ │ └── exercises.interface.ts
│ │ │ └── repository
│ │ │ │ ├── exercises-repository-memory.service.ts
│ │ │ │ └── exercises-repository.service.ts
│ │ ├── main.ts
│ │ ├── users
│ │ │ ├── db
│ │ │ │ └── users.data.ts
│ │ │ ├── dto
│ │ │ │ ├── create-users.dto.ts
│ │ │ │ └── get-users.dto.ts
│ │ │ ├── interface
│ │ │ │ └── users.interface.ts
│ │ │ ├── repository
│ │ │ │ ├── users-repository-memory.service.ts
│ │ │ │ └── users-repository.service.ts
│ │ │ ├── users.module.ts
│ │ │ └── users.service.ts
│ │ └── utils
│ │ │ ├── interfaces
│ │ │ ├── collection.interface.ts
│ │ │ ├── error.interface.ts
│ │ │ └── query.interface.ts
│ │ │ └── utils.ts
│ ├── test
│ │ ├── app.e2e-spec.ts
│ │ └── jest-e2e.json
│ ├── tsconfig.build.json
│ └── tsconfig.json
└── gym-diary
│ ├── .editorconfig
│ ├── .gitignore
│ ├── .vscode
│ ├── extensions.json
│ ├── launch.json
│ └── tasks.json
│ ├── README.md
│ ├── angular.json
│ ├── cypress.config.ts
│ ├── cypress
│ ├── e2e
│ │ ├── login.cy.ts
│ │ └── new-entry-form.cy.ts
│ ├── fixtures
│ │ └── example.json
│ ├── support
│ │ ├── commands.ts
│ │ ├── component-index.html
│ │ ├── component.ts
│ │ └── e2e.ts
│ └── tsconfig.json
│ ├── package-lock.json
│ ├── package.json
│ ├── prettier.config.js
│ ├── src
│ ├── app
│ │ ├── app-routing.module.ts
│ │ ├── app.component.css
│ │ ├── app.component.html
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── app.module.ts
│ │ ├── diary
│ │ │ ├── diary-routing.module.ts
│ │ │ ├── diary.module.ts
│ │ │ ├── diary.resolver.spec.ts
│ │ │ ├── diary.resolver.ts
│ │ │ ├── diary
│ │ │ │ ├── diary.component.css
│ │ │ │ ├── diary.component.html
│ │ │ │ ├── diary.component.spec.ts
│ │ │ │ └── diary.component.ts
│ │ │ ├── entry-item
│ │ │ │ ├── entry-item.component.css
│ │ │ │ ├── entry-item.component.html
│ │ │ │ ├── entry-item.component.spec.ts
│ │ │ │ └── entry-item.component.ts
│ │ │ ├── interfaces
│ │ │ │ ├── exercise-set.ts
│ │ │ │ └── exercise.ts
│ │ │ ├── list-entries
│ │ │ │ ├── list-entries.component.css
│ │ │ │ ├── list-entries.component.html
│ │ │ │ ├── list-entries.component.spec.ts
│ │ │ │ └── list-entries.component.ts
│ │ │ ├── new-entry-form-reactive
│ │ │ │ ├── custom-validation.ts
│ │ │ │ ├── new-entry-form-reactive.component.css
│ │ │ │ ├── new-entry-form-reactive.component.html
│ │ │ │ ├── new-entry-form-reactive.component.spec.ts
│ │ │ │ └── new-entry-form-reactive.component.ts
│ │ │ ├── new-entry-form-template
│ │ │ │ ├── new-entry-form-template.component.css
│ │ │ │ ├── new-entry-form-template.component.html
│ │ │ │ ├── new-entry-form-template.component.spec.ts
│ │ │ │ └── new-entry-form-template.component.ts
│ │ │ ├── new-item-button
│ │ │ │ ├── new-item-button.component.css
│ │ │ │ ├── new-item-button.component.html
│ │ │ │ ├── new-item-button.component.spec.ts
│ │ │ │ └── new-item-button.component.ts
│ │ │ └── services
│ │ │ │ ├── exercise-sets.service.spec.ts
│ │ │ │ ├── exercise-sets.service.ts
│ │ │ │ ├── exercises.service.spec.ts
│ │ │ │ └── exercises.service.ts
│ │ ├── error-page
│ │ │ ├── error-page.component.css
│ │ │ ├── error-page.component.html
│ │ │ ├── error-page.component.spec.ts
│ │ │ └── error-page.component.ts
│ │ ├── home
│ │ │ ├── home-routing.module.ts
│ │ │ ├── home.component.css
│ │ │ ├── home.component.html
│ │ │ ├── home.component.spec.ts
│ │ │ ├── home.component.ts
│ │ │ └── home.module.ts
│ │ ├── loading-overlay
│ │ │ ├── load.interceptor.spec.ts
│ │ │ ├── load.interceptor.ts
│ │ │ ├── load.service.spec.ts
│ │ │ ├── load.service.ts
│ │ │ ├── loading-overlay.component.css
│ │ │ ├── loading-overlay.component.html
│ │ │ ├── loading-overlay.component.spec.ts
│ │ │ └── loading-overlay.component.ts
│ │ ├── login
│ │ │ ├── auth.guard.spec.ts
│ │ │ ├── auth.guard.ts
│ │ │ ├── auth.interceptor.spec.ts
│ │ │ ├── auth.interceptor.ts
│ │ │ ├── auth.service.spec.ts
│ │ │ ├── auth.service.ts
│ │ │ ├── auth.ts
│ │ │ ├── login-routing.module.ts
│ │ │ ├── login.component.css
│ │ │ ├── login.component.html
│ │ │ ├── login.component.spec.ts
│ │ │ ├── login.component.ts
│ │ │ └── login.module.ts
│ │ ├── notification
│ │ │ ├── notification.interceptor.spec.ts
│ │ │ └── notification.interceptor.ts
│ │ ├── shared
│ │ │ ├── host.interceptor.spec.ts
│ │ │ └── host.interceptor.ts
│ │ └── telemetry
│ │ │ ├── telemetry.interceptor.spec.ts
│ │ │ └── telemetry.interceptor.ts
│ ├── assets
│ │ └── .gitkeep
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ └── styles.css
│ ├── tailwind.config.js
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ └── tsconfig.spec.json
├── ch11
├── gym-diary-backend
│ ├── .eslintrc.js
│ ├── .gitignore
│ ├── .prettierrc
│ ├── README.md
│ ├── nest-cli.json
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── app.controller.spec.ts
│ │ ├── app.controller.ts
│ │ ├── app.module.ts
│ │ ├── app.service.ts
│ │ ├── auth
│ │ │ ├── auth.controller.ts
│ │ │ ├── auth.guard.ts
│ │ │ ├── auth.module.ts
│ │ │ ├── auth.service.spec.ts
│ │ │ ├── auth.service.ts
│ │ │ ├── constants.ts
│ │ │ └── public.decorator.ts
│ │ ├── diary
│ │ │ ├── db
│ │ │ │ └── diary.data.ts
│ │ │ ├── diary.controller.ts
│ │ │ ├── diary.module.ts
│ │ │ ├── diary.service.ts
│ │ │ ├── dto
│ │ │ │ ├── create-diaries.dto.ts
│ │ │ │ └── get-diaries.dto.ts
│ │ │ ├── interface
│ │ │ │ └── diary.interface.ts
│ │ │ └── repository
│ │ │ │ ├── diary-repository-memory.service.ts
│ │ │ │ └── diary-repository.service.ts
│ │ ├── exercises
│ │ │ ├── db
│ │ │ │ └── exercises.data.ts
│ │ │ ├── dto
│ │ │ │ ├── create-exercises.dto.ts
│ │ │ │ └── get-exercises.dto.ts
│ │ │ ├── exercises.controller.ts
│ │ │ ├── exercises.module.ts
│ │ │ ├── exercises.service.ts
│ │ │ ├── interface
│ │ │ │ └── exercises.interface.ts
│ │ │ └── repository
│ │ │ │ ├── exercises-repository-memory.service.ts
│ │ │ │ └── exercises-repository.service.ts
│ │ ├── main.ts
│ │ ├── users
│ │ │ ├── db
│ │ │ │ └── users.data.ts
│ │ │ ├── dto
│ │ │ │ ├── create-users.dto.ts
│ │ │ │ └── get-users.dto.ts
│ │ │ ├── interface
│ │ │ │ └── users.interface.ts
│ │ │ ├── repository
│ │ │ │ ├── users-repository-memory.service.ts
│ │ │ │ └── users-repository.service.ts
│ │ │ ├── users.module.ts
│ │ │ └── users.service.ts
│ │ └── utils
│ │ │ ├── interfaces
│ │ │ ├── collection.interface.ts
│ │ │ ├── error.interface.ts
│ │ │ └── query.interface.ts
│ │ │ └── utils.ts
│ ├── test
│ │ ├── app.e2e-spec.ts
│ │ └── jest-e2e.json
│ ├── tsconfig.build.json
│ └── tsconfig.json
├── gym-diary
│ ├── .editorconfig
│ ├── .gitignore
│ ├── .vscode
│ │ ├── extensions.json
│ │ ├── launch.json
│ │ └── tasks.json
│ ├── README.md
│ ├── angular.json
│ ├── cypress.config.ts
│ ├── cypress
│ │ ├── e2e
│ │ │ ├── login.cy.ts
│ │ │ └── new-entry-form.cy.ts
│ │ ├── fixtures
│ │ │ └── example.json
│ │ ├── support
│ │ │ ├── commands.ts
│ │ │ ├── component-index.html
│ │ │ ├── component.ts
│ │ │ └── e2e.ts
│ │ └── tsconfig.json
│ ├── package-lock.json
│ ├── package.json
│ ├── prettier.config.js
│ ├── src
│ │ ├── app
│ │ │ ├── app-routing.module.ts
│ │ │ ├── app.component.css
│ │ │ ├── app.component.html
│ │ │ ├── app.component.spec.ts
│ │ │ ├── app.component.ts
│ │ │ ├── app.module.ts
│ │ │ ├── diary
│ │ │ │ ├── diary-routing.module.ts
│ │ │ │ ├── diary.module.ts
│ │ │ │ ├── diary.resolver.spec.ts
│ │ │ │ ├── diary.resolver.ts
│ │ │ │ ├── diary
│ │ │ │ │ ├── diary.component.css
│ │ │ │ │ ├── diary.component.html
│ │ │ │ │ ├── diary.component.spec.ts
│ │ │ │ │ └── diary.component.ts
│ │ │ │ ├── entry-item
│ │ │ │ │ ├── entry-item.component.css
│ │ │ │ │ ├── entry-item.component.html
│ │ │ │ │ ├── entry-item.component.spec.ts
│ │ │ │ │ └── entry-item.component.ts
│ │ │ │ ├── interfaces
│ │ │ │ │ ├── exercise-set.ts
│ │ │ │ │ └── exercise.ts
│ │ │ │ ├── list-entries
│ │ │ │ │ ├── list-entries.component.css
│ │ │ │ │ ├── list-entries.component.html
│ │ │ │ │ ├── list-entries.component.spec.ts
│ │ │ │ │ └── list-entries.component.ts
│ │ │ │ ├── new-entry-form-reactive
│ │ │ │ │ ├── custom-validation.ts
│ │ │ │ │ ├── new-entry-form-reactive.component.css
│ │ │ │ │ ├── new-entry-form-reactive.component.html
│ │ │ │ │ ├── new-entry-form-reactive.component.spec.ts
│ │ │ │ │ └── new-entry-form-reactive.component.ts
│ │ │ │ ├── new-entry-form-template
│ │ │ │ │ ├── new-entry-form-template.component.css
│ │ │ │ │ ├── new-entry-form-template.component.html
│ │ │ │ │ ├── new-entry-form-template.component.spec.ts
│ │ │ │ │ └── new-entry-form-template.component.ts
│ │ │ │ ├── new-item-button
│ │ │ │ │ ├── new-item-button.component.css
│ │ │ │ │ ├── new-item-button.component.html
│ │ │ │ │ ├── new-item-button.component.spec.ts
│ │ │ │ │ └── new-item-button.component.ts
│ │ │ │ └── services
│ │ │ │ │ ├── exercise-sets.service.spec.ts
│ │ │ │ │ ├── exercise-sets.service.ts
│ │ │ │ │ ├── exercises.service.spec.ts
│ │ │ │ │ └── exercises.service.ts
│ │ │ ├── error-page
│ │ │ │ ├── error-page.component.css
│ │ │ │ ├── error-page.component.html
│ │ │ │ ├── error-page.component.spec.ts
│ │ │ │ └── error-page.component.ts
│ │ │ ├── exercise
│ │ │ │ ├── exercise-routing.module.ts
│ │ │ │ ├── exercise.module.ts
│ │ │ │ └── exercise
│ │ │ │ │ ├── exercise.component.css
│ │ │ │ │ ├── exercise.component.cy.ts
│ │ │ │ │ ├── exercise.component.html
│ │ │ │ │ └── exercise.component.ts
│ │ │ ├── home
│ │ │ │ ├── home-routing.module.ts
│ │ │ │ ├── home.component.css
│ │ │ │ ├── home.component.html
│ │ │ │ ├── home.component.spec.ts
│ │ │ │ ├── home.component.ts
│ │ │ │ └── home.module.ts
│ │ │ ├── loading-overlay
│ │ │ │ ├── load.interceptor.spec.ts
│ │ │ │ ├── load.interceptor.ts
│ │ │ │ ├── load.service.spec.ts
│ │ │ │ ├── load.service.ts
│ │ │ │ ├── loading-overlay.component.css
│ │ │ │ ├── loading-overlay.component.html
│ │ │ │ ├── loading-overlay.component.spec.ts
│ │ │ │ └── loading-overlay.component.ts
│ │ │ ├── login
│ │ │ │ ├── auth.guard.spec.ts
│ │ │ │ ├── auth.guard.ts
│ │ │ │ ├── auth.interceptor.spec.ts
│ │ │ │ ├── auth.interceptor.ts
│ │ │ │ ├── auth.service.spec.ts
│ │ │ │ ├── auth.service.ts
│ │ │ │ ├── auth.ts
│ │ │ │ ├── login-routing.module.ts
│ │ │ │ ├── login.component.css
│ │ │ │ ├── login.component.html
│ │ │ │ ├── login.component.spec.ts
│ │ │ │ ├── login.component.ts
│ │ │ │ └── login.module.ts
│ │ │ ├── notification
│ │ │ │ ├── notification.interceptor.spec.ts
│ │ │ │ └── notification.interceptor.ts
│ │ │ ├── shared
│ │ │ │ ├── host.interceptor.spec.ts
│ │ │ │ └── host.interceptor.ts
│ │ │ └── telemetry
│ │ │ │ ├── telemetry.interceptor.spec.ts
│ │ │ │ └── telemetry.interceptor.ts
│ │ ├── assets
│ │ │ └── .gitkeep
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── main.ts
│ │ └── styles.css
│ ├── tailwind.config.js
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ └── tsconfig.spec.json
└── gym_exercises
│ ├── .editorconfig
│ ├── .gitignore
│ ├── .vscode
│ ├── extensions.json
│ ├── launch.json
│ └── tasks.json
│ ├── README.md
│ ├── angular.json
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ ├── app
│ │ ├── app.component.css
│ │ ├── app.component.html
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── app.config.ts
│ │ ├── exercise.ts
│ │ └── service
│ │ │ ├── exercises.service.spec.ts
│ │ │ └── exercises.service.ts
│ ├── assets
│ │ └── .gitkeep
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ └── styles.css
│ ├── tailwind.config.js
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ └── tsconfig.spec.json
├── ch12
├── gym-diary-backend
│ ├── .dockerignore
│ ├── .env.production
│ ├── .eslintrc.js
│ ├── .funcignore
│ ├── .gitignore
│ ├── .prettierrc
│ ├── .vscode
│ │ ├── extensions.json
│ │ ├── launch.json
│ │ ├── settings.json
│ │ └── tasks.json
│ ├── README.md
│ ├── dockerfile
│ ├── host.json
│ ├── local.settings.json
│ ├── main
│ │ ├── function.json
│ │ ├── index.ts
│ │ └── sample.dat
│ ├── nest-cli.json
│ ├── package-lock.json
│ ├── package.json
│ ├── proxies.json
│ ├── src
│ │ ├── app.controller.spec.ts
│ │ ├── app.controller.ts
│ │ ├── app.module.ts
│ │ ├── app.service.ts
│ │ ├── auth
│ │ │ ├── auth.controller.ts
│ │ │ ├── auth.guard.ts
│ │ │ ├── auth.module.ts
│ │ │ ├── auth.service.spec.ts
│ │ │ ├── auth.service.ts
│ │ │ ├── constants.ts
│ │ │ └── public.decorator.ts
│ │ ├── diary
│ │ │ ├── db
│ │ │ │ └── diary.data.ts
│ │ │ ├── diary.controller.ts
│ │ │ ├── diary.module.ts
│ │ │ ├── diary.service.ts
│ │ │ ├── dto
│ │ │ │ ├── create-diaries.dto.ts
│ │ │ │ └── get-diaries.dto.ts
│ │ │ ├── interface
│ │ │ │ └── diary.interface.ts
│ │ │ └── repository
│ │ │ │ ├── diary-repository-memory.service.ts
│ │ │ │ └── diary-repository.service.ts
│ │ ├── exercises
│ │ │ ├── db
│ │ │ │ └── exercises.data.ts
│ │ │ ├── dto
│ │ │ │ ├── create-exercises.dto.ts
│ │ │ │ └── get-exercises.dto.ts
│ │ │ ├── exercises.controller.ts
│ │ │ ├── exercises.module.ts
│ │ │ ├── exercises.service.ts
│ │ │ ├── interface
│ │ │ │ └── exercises.interface.ts
│ │ │ └── repository
│ │ │ │ ├── exercises-repository-memory.service.ts
│ │ │ │ └── exercises-repository.service.ts
│ │ ├── main.azure.ts
│ │ ├── main.ts
│ │ ├── users
│ │ │ ├── db
│ │ │ │ └── users.data.ts
│ │ │ ├── dto
│ │ │ │ ├── create-users.dto.ts
│ │ │ │ └── get-users.dto.ts
│ │ │ ├── interface
│ │ │ │ └── users.interface.ts
│ │ │ ├── repository
│ │ │ │ ├── users-repository-memory.service.ts
│ │ │ │ └── users-repository.service.ts
│ │ │ ├── users.module.ts
│ │ │ └── users.service.ts
│ │ └── utils
│ │ │ ├── interfaces
│ │ │ ├── collection.interface.ts
│ │ │ ├── error.interface.ts
│ │ │ └── query.interface.ts
│ │ │ └── utils.ts
│ ├── test
│ │ ├── app.e2e-spec.ts
│ │ └── jest-e2e.json
│ ├── tsconfig.build.json
│ └── tsconfig.json
├── gym-diary
│ ├── .dockerignore
│ ├── .editorconfig
│ ├── .gitignore
│ ├── .vscode
│ │ ├── extensions.json
│ │ ├── launch.json
│ │ └── tasks.json
│ ├── README.md
│ ├── angular.json
│ ├── cypress.config.ts
│ ├── cypress
│ │ ├── e2e
│ │ │ ├── login.cy.ts
│ │ │ └── new-entry-form.cy.ts
│ │ ├── fixtures
│ │ │ └── example.json
│ │ ├── support
│ │ │ ├── commands.ts
│ │ │ ├── component-index.html
│ │ │ ├── component.ts
│ │ │ └── e2e.ts
│ │ └── tsconfig.json
│ ├── dockerfile
│ ├── nginx.default.conf
│ ├── package-lock.json
│ ├── package.json
│ ├── prettier.config.js
│ ├── src
│ │ ├── app
│ │ │ ├── app-routing.module.ts
│ │ │ ├── app.component.css
│ │ │ ├── app.component.html
│ │ │ ├── app.component.spec.ts
│ │ │ ├── app.component.ts
│ │ │ ├── app.module.ts
│ │ │ ├── diary
│ │ │ │ ├── diary-routing.module.ts
│ │ │ │ ├── diary.module.ts
│ │ │ │ ├── diary.resolver.spec.ts
│ │ │ │ ├── diary.resolver.ts
│ │ │ │ ├── diary
│ │ │ │ │ ├── diary.component.css
│ │ │ │ │ ├── diary.component.html
│ │ │ │ │ ├── diary.component.spec.ts
│ │ │ │ │ └── diary.component.ts
│ │ │ │ ├── entry-item
│ │ │ │ │ ├── entry-item.component.css
│ │ │ │ │ ├── entry-item.component.html
│ │ │ │ │ ├── entry-item.component.spec.ts
│ │ │ │ │ └── entry-item.component.ts
│ │ │ │ ├── interfaces
│ │ │ │ │ ├── exercise-set.ts
│ │ │ │ │ └── exercise.ts
│ │ │ │ ├── list-entries
│ │ │ │ │ ├── list-entries.component.css
│ │ │ │ │ ├── list-entries.component.html
│ │ │ │ │ ├── list-entries.component.spec.ts
│ │ │ │ │ └── list-entries.component.ts
│ │ │ │ ├── new-entry-form-reactive
│ │ │ │ │ ├── custom-validation.ts
│ │ │ │ │ ├── new-entry-form-reactive.component.css
│ │ │ │ │ ├── new-entry-form-reactive.component.html
│ │ │ │ │ ├── new-entry-form-reactive.component.spec.ts
│ │ │ │ │ └── new-entry-form-reactive.component.ts
│ │ │ │ ├── new-entry-form-template
│ │ │ │ │ ├── new-entry-form-template.component.css
│ │ │ │ │ ├── new-entry-form-template.component.html
│ │ │ │ │ ├── new-entry-form-template.component.spec.ts
│ │ │ │ │ └── new-entry-form-template.component.ts
│ │ │ │ ├── new-item-button
│ │ │ │ │ ├── new-item-button.component.css
│ │ │ │ │ ├── new-item-button.component.html
│ │ │ │ │ ├── new-item-button.component.spec.ts
│ │ │ │ │ └── new-item-button.component.ts
│ │ │ │ └── services
│ │ │ │ │ ├── exercise-sets.service.spec.ts
│ │ │ │ │ ├── exercise-sets.service.ts
│ │ │ │ │ ├── exercises.service.spec.ts
│ │ │ │ │ └── exercises.service.ts
│ │ │ ├── error-page
│ │ │ │ ├── error-page.component.css
│ │ │ │ ├── error-page.component.html
│ │ │ │ ├── error-page.component.spec.ts
│ │ │ │ └── error-page.component.ts
│ │ │ ├── exercise
│ │ │ │ ├── exercise-routing.module.ts
│ │ │ │ ├── exercise.module.ts
│ │ │ │ └── exercise
│ │ │ │ │ ├── exercise.component.css
│ │ │ │ │ ├── exercise.component.cy.ts
│ │ │ │ │ ├── exercise.component.html
│ │ │ │ │ └── exercise.component.ts
│ │ │ ├── home
│ │ │ │ ├── home-routing.module.ts
│ │ │ │ ├── home.component.css
│ │ │ │ ├── home.component.html
│ │ │ │ ├── home.component.spec.ts
│ │ │ │ ├── home.component.ts
│ │ │ │ └── home.module.ts
│ │ │ ├── loading-overlay
│ │ │ │ ├── load.interceptor.spec.ts
│ │ │ │ ├── load.interceptor.ts
│ │ │ │ ├── load.service.spec.ts
│ │ │ │ ├── load.service.ts
│ │ │ │ ├── loading-overlay.component.css
│ │ │ │ ├── loading-overlay.component.html
│ │ │ │ ├── loading-overlay.component.spec.ts
│ │ │ │ └── loading-overlay.component.ts
│ │ │ ├── login
│ │ │ │ ├── auth.guard.spec.ts
│ │ │ │ ├── auth.guard.ts
│ │ │ │ ├── auth.interceptor.spec.ts
│ │ │ │ ├── auth.interceptor.ts
│ │ │ │ ├── auth.service.spec.ts
│ │ │ │ ├── auth.service.ts
│ │ │ │ ├── auth.ts
│ │ │ │ ├── login-routing.module.ts
│ │ │ │ ├── login.component.css
│ │ │ │ ├── login.component.html
│ │ │ │ ├── login.component.spec.ts
│ │ │ │ ├── login.component.ts
│ │ │ │ └── login.module.ts
│ │ │ ├── notification
│ │ │ │ ├── notification.interceptor.spec.ts
│ │ │ │ └── notification.interceptor.ts
│ │ │ ├── shared
│ │ │ │ ├── host.interceptor.spec.ts
│ │ │ │ └── host.interceptor.ts
│ │ │ └── telemetry
│ │ │ │ ├── telemetry.interceptor.spec.ts
│ │ │ │ └── telemetry.interceptor.ts
│ │ ├── assets
│ │ │ └── .gitkeep
│ │ ├── environments
│ │ │ ├── environment.development.ts
│ │ │ └── environment.ts
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── main.ts
│ │ └── styles.css
│ ├── tailwind.config.js
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ └── tsconfig.spec.json
└── gym_exercises
│ ├── .editorconfig
│ ├── .gitignore
│ ├── .vscode
│ ├── extensions.json
│ ├── launch.json
│ └── tasks.json
│ ├── README.md
│ ├── angular.json
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ ├── app
│ │ ├── app.component.css
│ │ ├── app.component.html
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── app.config.ts
│ │ ├── exercise.ts
│ │ └── service
│ │ │ ├── exercises.service.spec.ts
│ │ │ └── exercises.service.ts
│ ├── assets
│ │ └── .gitkeep
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ └── styles.css
│ ├── tailwind.config.js
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ └── tsconfig.spec.json
├── ch13
├── gym-diary-backend
│ ├── .dockerignore
│ ├── .env.production
│ ├── .eslintrc.js
│ ├── .funcignore
│ ├── .gitignore
│ ├── .prettierrc
│ ├── .vscode
│ │ ├── extensions.json
│ │ ├── launch.json
│ │ ├── settings.json
│ │ └── tasks.json
│ ├── README.md
│ ├── dockerfile
│ ├── host.json
│ ├── local.settings.json
│ ├── main
│ │ ├── function.json
│ │ ├── index.ts
│ │ └── sample.dat
│ ├── nest-cli.json
│ ├── package-lock.json
│ ├── package.json
│ ├── proxies.json
│ ├── src
│ │ ├── app.controller.spec.ts
│ │ ├── app.controller.ts
│ │ ├── app.module.ts
│ │ ├── app.service.ts
│ │ ├── auth
│ │ │ ├── auth.controller.ts
│ │ │ ├── auth.guard.ts
│ │ │ ├── auth.module.ts
│ │ │ ├── auth.service.spec.ts
│ │ │ ├── auth.service.ts
│ │ │ ├── constants.ts
│ │ │ └── public.decorator.ts
│ │ ├── diary
│ │ │ ├── db
│ │ │ │ └── diary.data.ts
│ │ │ ├── diary.controller.ts
│ │ │ ├── diary.module.ts
│ │ │ ├── diary.service.ts
│ │ │ ├── dto
│ │ │ │ ├── create-diaries.dto.ts
│ │ │ │ └── get-diaries.dto.ts
│ │ │ ├── interface
│ │ │ │ └── diary.interface.ts
│ │ │ └── repository
│ │ │ │ ├── diary-repository-memory.service.ts
│ │ │ │ └── diary-repository.service.ts
│ │ ├── exercises
│ │ │ ├── db
│ │ │ │ └── exercises.data.ts
│ │ │ ├── dto
│ │ │ │ ├── create-exercises.dto.ts
│ │ │ │ └── get-exercises.dto.ts
│ │ │ ├── exercises.controller.ts
│ │ │ ├── exercises.module.ts
│ │ │ ├── exercises.service.ts
│ │ │ ├── interface
│ │ │ │ └── exercises.interface.ts
│ │ │ └── repository
│ │ │ │ ├── exercises-repository-memory.service.ts
│ │ │ │ └── exercises-repository.service.ts
│ │ ├── main.azure.ts
│ │ ├── main.ts
│ │ ├── users
│ │ │ ├── db
│ │ │ │ └── users.data.ts
│ │ │ ├── dto
│ │ │ │ ├── create-users.dto.ts
│ │ │ │ └── get-users.dto.ts
│ │ │ ├── interface
│ │ │ │ └── users.interface.ts
│ │ │ ├── repository
│ │ │ │ ├── users-repository-memory.service.ts
│ │ │ │ └── users-repository.service.ts
│ │ │ ├── users.module.ts
│ │ │ └── users.service.ts
│ │ └── utils
│ │ │ ├── interfaces
│ │ │ ├── collection.interface.ts
│ │ │ ├── error.interface.ts
│ │ │ └── query.interface.ts
│ │ │ └── utils.ts
│ ├── test
│ │ ├── app.e2e-spec.ts
│ │ └── jest-e2e.json
│ ├── tsconfig.build.json
│ └── tsconfig.json
├── gym-diary
│ ├── .dockerignore
│ ├── .editorconfig
│ ├── .gitignore
│ ├── .vscode
│ │ ├── extensions.json
│ │ ├── launch.json
│ │ └── tasks.json
│ ├── README.md
│ ├── angular.json
│ ├── cypress.config.ts
│ ├── cypress
│ │ ├── e2e
│ │ │ ├── login.cy.ts
│ │ │ └── new-entry-form.cy.ts
│ │ ├── fixtures
│ │ │ └── example.json
│ │ ├── support
│ │ │ ├── commands.ts
│ │ │ ├── component-index.html
│ │ │ ├── component.ts
│ │ │ └── e2e.ts
│ │ └── tsconfig.json
│ ├── dockerfile
│ ├── nginx.default.conf
│ ├── package-lock.json
│ ├── package.json
│ ├── prettier.config.js
│ ├── src
│ │ ├── app
│ │ │ ├── app-routing.module.ts
│ │ │ ├── app.component.css
│ │ │ ├── app.component.html
│ │ │ ├── app.component.spec.ts
│ │ │ ├── app.component.ts
│ │ │ ├── app.module.ts
│ │ │ ├── diary
│ │ │ │ ├── diary-routing.module.ts
│ │ │ │ ├── diary.module.ts
│ │ │ │ ├── diary.resolver.spec.ts
│ │ │ │ ├── diary.resolver.ts
│ │ │ │ ├── diary
│ │ │ │ │ ├── diary.component.css
│ │ │ │ │ ├── diary.component.html
│ │ │ │ │ ├── diary.component.spec.ts
│ │ │ │ │ └── diary.component.ts
│ │ │ │ ├── entry-item
│ │ │ │ │ ├── entry-item.component.css
│ │ │ │ │ ├── entry-item.component.html
│ │ │ │ │ ├── entry-item.component.spec.ts
│ │ │ │ │ └── entry-item.component.ts
│ │ │ │ ├── interfaces
│ │ │ │ │ ├── exercise-set.ts
│ │ │ │ │ └── exercise.ts
│ │ │ │ ├── list-entries
│ │ │ │ │ ├── list-entries.component.css
│ │ │ │ │ ├── list-entries.component.html
│ │ │ │ │ ├── list-entries.component.spec.ts
│ │ │ │ │ └── list-entries.component.ts
│ │ │ │ ├── new-entry-form-reactive
│ │ │ │ │ ├── custom-validation.ts
│ │ │ │ │ ├── new-entry-form-reactive.component.css
│ │ │ │ │ ├── new-entry-form-reactive.component.html
│ │ │ │ │ ├── new-entry-form-reactive.component.spec.ts
│ │ │ │ │ └── new-entry-form-reactive.component.ts
│ │ │ │ ├── new-entry-form-template
│ │ │ │ │ ├── new-entry-form-template.component.css
│ │ │ │ │ ├── new-entry-form-template.component.html
│ │ │ │ │ ├── new-entry-form-template.component.spec.ts
│ │ │ │ │ └── new-entry-form-template.component.ts
│ │ │ │ ├── new-item-button
│ │ │ │ │ ├── new-item-button.component.css
│ │ │ │ │ ├── new-item-button.component.html
│ │ │ │ │ ├── new-item-button.component.spec.ts
│ │ │ │ │ └── new-item-button.component.ts
│ │ │ │ └── services
│ │ │ │ │ ├── exercise-sets.service.spec.ts
│ │ │ │ │ ├── exercise-sets.service.ts
│ │ │ │ │ ├── exercises.service.spec.ts
│ │ │ │ │ └── exercises.service.ts
│ │ │ ├── error-page
│ │ │ │ ├── error-page.component.css
│ │ │ │ ├── error-page.component.html
│ │ │ │ ├── error-page.component.spec.ts
│ │ │ │ └── error-page.component.ts
│ │ │ ├── exercise
│ │ │ │ ├── exercise-routing.module.ts
│ │ │ │ ├── exercise.module.ts
│ │ │ │ └── exercise
│ │ │ │ │ ├── exercise.component.css
│ │ │ │ │ ├── exercise.component.cy.ts
│ │ │ │ │ ├── exercise.component.html
│ │ │ │ │ └── exercise.component.ts
│ │ │ ├── home
│ │ │ │ ├── home-routing.module.ts
│ │ │ │ ├── home.component.css
│ │ │ │ ├── home.component.html
│ │ │ │ ├── home.component.spec.ts
│ │ │ │ ├── home.component.ts
│ │ │ │ └── home.module.ts
│ │ │ ├── loading-overlay
│ │ │ │ ├── load.interceptor.spec.ts
│ │ │ │ ├── load.interceptor.ts
│ │ │ │ ├── load.service.spec.ts
│ │ │ │ ├── load.service.ts
│ │ │ │ ├── loading-overlay.component.css
│ │ │ │ ├── loading-overlay.component.html
│ │ │ │ ├── loading-overlay.component.spec.ts
│ │ │ │ └── loading-overlay.component.ts
│ │ │ ├── login
│ │ │ │ ├── auth.guard.spec.ts
│ │ │ │ ├── auth.guard.ts
│ │ │ │ ├── auth.interceptor.spec.ts
│ │ │ │ ├── auth.interceptor.ts
│ │ │ │ ├── auth.service.spec.ts
│ │ │ │ ├── auth.service.ts
│ │ │ │ ├── auth.ts
│ │ │ │ ├── login-routing.module.ts
│ │ │ │ ├── login.component.css
│ │ │ │ ├── login.component.html
│ │ │ │ ├── login.component.spec.ts
│ │ │ │ ├── login.component.ts
│ │ │ │ └── login.module.ts
│ │ │ ├── notification
│ │ │ │ ├── notification.interceptor.spec.ts
│ │ │ │ └── notification.interceptor.ts
│ │ │ ├── shared
│ │ │ │ ├── host.interceptor.spec.ts
│ │ │ │ └── host.interceptor.ts
│ │ │ └── telemetry
│ │ │ │ ├── telemetry.interceptor.spec.ts
│ │ │ │ └── telemetry.interceptor.ts
│ │ ├── assets
│ │ │ └── .gitkeep
│ │ ├── environments
│ │ │ ├── environment.development.ts
│ │ │ └── environment.ts
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── main.ts
│ │ └── styles.css
│ ├── tailwind.config.js
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ └── tsconfig.spec.json
└── gym_exercises
│ ├── .editorconfig
│ ├── .gitignore
│ ├── .vscode
│ ├── extensions.json
│ ├── launch.json
│ └── tasks.json
│ ├── README.md
│ ├── angular.json
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ ├── app
│ │ ├── app.component.css
│ │ ├── app.component.html
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── app.config.ts
│ │ ├── exercise.ts
│ │ └── service
│ │ │ ├── exercises.service.spec.ts
│ │ │ └── exercises.service.ts
│ ├── assets
│ │ └── .gitkeep
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ └── styles.css
│ ├── tailwind.config.js
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ └── tsconfig.spec.json
├── ch2
├── jsmodule_example
│ ├── index.mjs
│ ├── package.json
│ └── sum.mjs
└── talktalk
│ ├── .editorconfig
│ ├── .gitignore
│ ├── .vscode
│ ├── extensions.json
│ ├── launch.json
│ └── tasks.json
│ ├── README.md
│ ├── angular.json
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ ├── app
│ │ ├── app-routing.module.ts
│ │ ├── app.component.css
│ │ ├── app.component.html
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── app.module.ts
│ │ ├── home
│ │ │ ├── home-routing.module.ts
│ │ │ ├── home.module.ts
│ │ │ └── home
│ │ │ │ ├── home.component.css
│ │ │ │ ├── home.component.html
│ │ │ │ ├── home.component.spec.ts
│ │ │ │ └── home.component.ts
│ │ └── shared
│ │ │ └── shared.module.ts
│ ├── assets
│ │ └── .gitkeep
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ └── styles.css
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ └── tsconfig.spec.json
├── ch3
└── typescript-example
│ ├── build
│ ├── basic_types
│ │ ├── animals.js
│ │ ├── any.js
│ │ ├── array.js
│ │ ├── classes_basic.js
│ │ ├── interface_basic.js
│ │ └── primitive.js
│ └── index.js
│ ├── nodemon.json
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ ├── basic_types
│ │ ├── animals.ts
│ │ ├── any.ts
│ │ ├── array.ts
│ │ ├── classes_basic.ts
│ │ ├── interface_basic.ts
│ │ ├── primitive.ts
│ │ ├── type_function.ts
│ │ ├── type_guard.ts
│ │ └── types_basic.ts
│ └── index.ts
│ └── tsconfig.json
├── ch4
└── gym-diary
│ ├── .editorconfig
│ ├── .gitignore
│ ├── .vscode
│ ├── extensions.json
│ ├── launch.json
│ └── tasks.json
│ ├── README.md
│ ├── angular.json
│ ├── package-lock.json
│ ├── package.json
│ ├── prettier.config.js
│ ├── src
│ ├── app
│ │ ├── app-routing.module.ts
│ │ ├── app.component.css
│ │ ├── app.component.html
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── app.module.ts
│ │ └── diary
│ │ │ ├── diary-routing.module.ts
│ │ │ ├── diary.module.ts
│ │ │ ├── diary
│ │ │ ├── diary.component.css
│ │ │ ├── diary.component.html
│ │ │ ├── diary.component.spec.ts
│ │ │ └── diary.component.ts
│ │ │ ├── entry-item
│ │ │ ├── entry-item.component.css
│ │ │ ├── entry-item.component.html
│ │ │ ├── entry-item.component.spec.ts
│ │ │ └── entry-item.component.ts
│ │ │ ├── interfaces
│ │ │ └── exercise-set.ts
│ │ │ ├── list-entries
│ │ │ ├── list-entries.component.css
│ │ │ ├── list-entries.component.html
│ │ │ ├── list-entries.component.spec.ts
│ │ │ └── list-entries.component.ts
│ │ │ └── new-item-button
│ │ │ ├── new-item-button.component.css
│ │ │ ├── new-item-button.component.html
│ │ │ ├── new-item-button.component.spec.ts
│ │ │ └── new-item-button.component.ts
│ ├── assets
│ │ └── .gitkeep
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ └── styles.css
│ ├── tailwind.config.js
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ └── tsconfig.spec.json
├── ch5
├── gym-diary-backend
│ ├── .eslintrc.js
│ ├── .gitignore
│ ├── .prettierrc
│ ├── README.md
│ ├── nest-cli.json
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── app.controller.spec.ts
│ │ ├── app.controller.ts
│ │ ├── app.module.ts
│ │ ├── app.service.ts
│ │ ├── auth
│ │ │ ├── auth.controller.ts
│ │ │ ├── auth.guard.ts
│ │ │ ├── auth.module.ts
│ │ │ ├── auth.service.spec.ts
│ │ │ ├── auth.service.ts
│ │ │ ├── constants.ts
│ │ │ └── public.decorator.ts
│ │ ├── diary
│ │ │ ├── db
│ │ │ │ └── diary.data.ts
│ │ │ ├── diary.controller.ts
│ │ │ ├── diary.module.ts
│ │ │ ├── dto
│ │ │ │ ├── create-diaries.dto.ts
│ │ │ │ └── get-diaries.dto.ts
│ │ │ ├── exercises.service.ts
│ │ │ ├── interface
│ │ │ │ └── diary.interface.ts
│ │ │ └── repository
│ │ │ │ ├── diary-repository-memory.service.ts
│ │ │ │ └── diary-repository.service.ts
│ │ ├── exercises
│ │ │ ├── db
│ │ │ │ └── exercises.data.ts
│ │ │ ├── dto
│ │ │ │ ├── create-exercises.dto.ts
│ │ │ │ └── get-exercises.dto.ts
│ │ │ ├── exercises.controller.ts
│ │ │ ├── exercises.module.ts
│ │ │ ├── exercises.service.ts
│ │ │ ├── interface
│ │ │ │ └── exercises.interface.ts
│ │ │ └── repository
│ │ │ │ ├── exercises-repository-memory.service.ts
│ │ │ │ └── exercises-repository.service.ts
│ │ ├── main.ts
│ │ ├── users
│ │ │ ├── db
│ │ │ │ └── users.data.ts
│ │ │ ├── dto
│ │ │ │ ├── create-users.dto.ts
│ │ │ │ └── get-users.dto.ts
│ │ │ ├── interface
│ │ │ │ └── users.interface.ts
│ │ │ ├── repository
│ │ │ │ ├── users-repository-memory.service.ts
│ │ │ │ └── users-repository.service.ts
│ │ │ ├── users.module.ts
│ │ │ └── users.service.ts
│ │ └── utils
│ │ │ ├── interfaces
│ │ │ ├── collection.interface.ts
│ │ │ ├── error.interface.ts
│ │ │ └── query.interface.ts
│ │ │ └── utils.ts
│ ├── test
│ │ ├── app.e2e-spec.ts
│ │ └── jest-e2e.json
│ ├── tsconfig.build.json
│ └── tsconfig.json
└── gym-diary
│ ├── .editorconfig
│ ├── .gitignore
│ ├── .vscode
│ ├── extensions.json
│ ├── launch.json
│ └── tasks.json
│ ├── README.md
│ ├── angular.json
│ ├── package-lock.json
│ ├── package.json
│ ├── prettier.config.js
│ ├── src
│ ├── app
│ │ ├── app-routing.module.ts
│ │ ├── app.component.css
│ │ ├── app.component.html
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── app.module.ts
│ │ └── diary
│ │ │ ├── diary-routing.module.ts
│ │ │ ├── diary.module.ts
│ │ │ ├── diary
│ │ │ ├── diary.component.css
│ │ │ ├── diary.component.html
│ │ │ ├── diary.component.spec.ts
│ │ │ └── diary.component.ts
│ │ │ ├── entry-item
│ │ │ ├── entry-item.component.css
│ │ │ ├── entry-item.component.html
│ │ │ ├── entry-item.component.spec.ts
│ │ │ └── entry-item.component.ts
│ │ │ ├── interfaces
│ │ │ └── exercise-set.ts
│ │ │ ├── list-entries
│ │ │ ├── list-entries.component.css
│ │ │ ├── list-entries.component.html
│ │ │ ├── list-entries.component.spec.ts
│ │ │ └── list-entries.component.ts
│ │ │ ├── new-item-button
│ │ │ ├── new-item-button.component.css
│ │ │ ├── new-item-button.component.html
│ │ │ ├── new-item-button.component.spec.ts
│ │ │ └── new-item-button.component.ts
│ │ │ └── services
│ │ │ ├── exercise-sets.service.spec.ts
│ │ │ └── exercise-sets.service.ts
│ ├── assets
│ │ └── .gitkeep
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ └── styles.css
│ ├── tailwind.config.js
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ └── tsconfig.spec.json
├── ch6
├── gym-diary-backend
│ ├── .eslintrc.js
│ ├── .gitignore
│ ├── .prettierrc
│ ├── README.md
│ ├── nest-cli.json
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── app.controller.spec.ts
│ │ ├── app.controller.ts
│ │ ├── app.module.ts
│ │ ├── app.service.ts
│ │ ├── auth
│ │ │ ├── auth.controller.ts
│ │ │ ├── auth.guard.ts
│ │ │ ├── auth.module.ts
│ │ │ ├── auth.service.spec.ts
│ │ │ ├── auth.service.ts
│ │ │ ├── constants.ts
│ │ │ └── public.decorator.ts
│ │ ├── diary
│ │ │ ├── db
│ │ │ │ └── diary.data.ts
│ │ │ ├── diary.controller.ts
│ │ │ ├── diary.module.ts
│ │ │ ├── dto
│ │ │ │ ├── create-diaries.dto.ts
│ │ │ │ └── get-diaries.dto.ts
│ │ │ ├── exercises.service.ts
│ │ │ ├── interface
│ │ │ │ └── diary.interface.ts
│ │ │ └── repository
│ │ │ │ ├── diary-repository-memory.service.ts
│ │ │ │ └── diary-repository.service.ts
│ │ ├── exercises
│ │ │ ├── db
│ │ │ │ └── exercises.data.ts
│ │ │ ├── dto
│ │ │ │ ├── create-exercises.dto.ts
│ │ │ │ └── get-exercises.dto.ts
│ │ │ ├── exercises.controller.ts
│ │ │ ├── exercises.module.ts
│ │ │ ├── exercises.service.ts
│ │ │ ├── interface
│ │ │ │ └── exercises.interface.ts
│ │ │ └── repository
│ │ │ │ ├── exercises-repository-memory.service.ts
│ │ │ │ └── exercises-repository.service.ts
│ │ ├── main.ts
│ │ ├── users
│ │ │ ├── db
│ │ │ │ └── users.data.ts
│ │ │ ├── dto
│ │ │ │ ├── create-users.dto.ts
│ │ │ │ └── get-users.dto.ts
│ │ │ ├── interface
│ │ │ │ └── users.interface.ts
│ │ │ ├── repository
│ │ │ │ ├── users-repository-memory.service.ts
│ │ │ │ └── users-repository.service.ts
│ │ │ ├── users.module.ts
│ │ │ └── users.service.ts
│ │ └── utils
│ │ │ ├── interfaces
│ │ │ ├── collection.interface.ts
│ │ │ ├── error.interface.ts
│ │ │ └── query.interface.ts
│ │ │ └── utils.ts
│ ├── test
│ │ ├── app.e2e-spec.ts
│ │ └── jest-e2e.json
│ ├── tsconfig.build.json
│ └── tsconfig.json
└── gym-diary
│ ├── .editorconfig
│ ├── .gitignore
│ ├── .vscode
│ ├── extensions.json
│ ├── launch.json
│ └── tasks.json
│ ├── README.md
│ ├── angular.json
│ ├── package-lock.json
│ ├── package.json
│ ├── prettier.config.js
│ ├── src
│ ├── app
│ │ ├── app-routing.module.ts
│ │ ├── app.component.css
│ │ ├── app.component.html
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── app.module.ts
│ │ └── diary
│ │ │ ├── diary-routing.module.ts
│ │ │ ├── diary.module.ts
│ │ │ ├── diary
│ │ │ ├── diary.component.css
│ │ │ ├── diary.component.html
│ │ │ ├── diary.component.spec.ts
│ │ │ └── diary.component.ts
│ │ │ ├── entry-item
│ │ │ ├── entry-item.component.css
│ │ │ ├── entry-item.component.html
│ │ │ ├── entry-item.component.spec.ts
│ │ │ └── entry-item.component.ts
│ │ │ ├── interfaces
│ │ │ └── exercise-set.ts
│ │ │ ├── list-entries
│ │ │ ├── list-entries.component.css
│ │ │ ├── list-entries.component.html
│ │ │ ├── list-entries.component.spec.ts
│ │ │ └── list-entries.component.ts
│ │ │ ├── new-entry-form-reactive
│ │ │ ├── custom-validation.ts
│ │ │ ├── new-entry-form-reactive.component.css
│ │ │ ├── new-entry-form-reactive.component.html
│ │ │ ├── new-entry-form-reactive.component.spec.ts
│ │ │ └── new-entry-form-reactive.component.ts
│ │ │ ├── new-entry-form-template
│ │ │ ├── new-entry-form-template.component.css
│ │ │ ├── new-entry-form-template.component.html
│ │ │ ├── new-entry-form-template.component.spec.ts
│ │ │ └── new-entry-form-template.component.ts
│ │ │ ├── new-item-button
│ │ │ ├── new-item-button.component.css
│ │ │ ├── new-item-button.component.html
│ │ │ ├── new-item-button.component.spec.ts
│ │ │ └── new-item-button.component.ts
│ │ │ └── services
│ │ │ ├── exercise-sets.service.spec.ts
│ │ │ └── exercise-sets.service.ts
│ ├── assets
│ │ └── .gitkeep
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ └── styles.css
│ ├── tailwind.config.js
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ └── tsconfig.spec.json
├── ch7
├── gym-diary-backend
│ ├── .eslintrc.js
│ ├── .gitignore
│ ├── .prettierrc
│ ├── README.md
│ ├── nest-cli.json
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── app.controller.spec.ts
│ │ ├── app.controller.ts
│ │ ├── app.module.ts
│ │ ├── app.service.ts
│ │ ├── auth
│ │ │ ├── auth.controller.ts
│ │ │ ├── auth.guard.ts
│ │ │ ├── auth.module.ts
│ │ │ ├── auth.service.spec.ts
│ │ │ ├── auth.service.ts
│ │ │ ├── constants.ts
│ │ │ └── public.decorator.ts
│ │ ├── diary
│ │ │ ├── db
│ │ │ │ └── diary.data.ts
│ │ │ ├── diary.controller.ts
│ │ │ ├── diary.module.ts
│ │ │ ├── dto
│ │ │ │ ├── create-diaries.dto.ts
│ │ │ │ └── get-diaries.dto.ts
│ │ │ ├── exercises.service.ts
│ │ │ ├── interface
│ │ │ │ └── diary.interface.ts
│ │ │ └── repository
│ │ │ │ ├── diary-repository-memory.service.ts
│ │ │ │ └── diary-repository.service.ts
│ │ ├── exercises
│ │ │ ├── db
│ │ │ │ └── exercises.data.ts
│ │ │ ├── dto
│ │ │ │ ├── create-exercises.dto.ts
│ │ │ │ └── get-exercises.dto.ts
│ │ │ ├── exercises.controller.ts
│ │ │ ├── exercises.module.ts
│ │ │ ├── exercises.service.ts
│ │ │ ├── interface
│ │ │ │ └── exercises.interface.ts
│ │ │ └── repository
│ │ │ │ ├── exercises-repository-memory.service.ts
│ │ │ │ └── exercises-repository.service.ts
│ │ ├── main.ts
│ │ ├── users
│ │ │ ├── db
│ │ │ │ └── users.data.ts
│ │ │ ├── dto
│ │ │ │ ├── create-users.dto.ts
│ │ │ │ └── get-users.dto.ts
│ │ │ ├── interface
│ │ │ │ └── users.interface.ts
│ │ │ ├── repository
│ │ │ │ ├── users-repository-memory.service.ts
│ │ │ │ └── users-repository.service.ts
│ │ │ ├── users.module.ts
│ │ │ └── users.service.ts
│ │ └── utils
│ │ │ ├── interfaces
│ │ │ ├── collection.interface.ts
│ │ │ ├── error.interface.ts
│ │ │ └── query.interface.ts
│ │ │ └── utils.ts
│ ├── test
│ │ ├── app.e2e-spec.ts
│ │ └── jest-e2e.json
│ ├── tsconfig.build.json
│ └── tsconfig.json
└── gym-diary
│ ├── .editorconfig
│ ├── .gitignore
│ ├── .vscode
│ ├── extensions.json
│ ├── launch.json
│ └── tasks.json
│ ├── README.md
│ ├── angular.json
│ ├── package-lock.json
│ ├── package.json
│ ├── prettier.config.js
│ ├── src
│ ├── app
│ │ ├── app-routing.module.ts
│ │ ├── app.component.css
│ │ ├── app.component.html
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── app.module.ts
│ │ ├── diary
│ │ │ ├── diary-routing.module.ts
│ │ │ ├── diary.module.ts
│ │ │ ├── diary.resolver.spec.ts
│ │ │ ├── diary.resolver.ts
│ │ │ ├── diary
│ │ │ │ ├── diary.component.css
│ │ │ │ ├── diary.component.html
│ │ │ │ ├── diary.component.spec.ts
│ │ │ │ └── diary.component.ts
│ │ │ ├── entry-item
│ │ │ │ ├── entry-item.component.css
│ │ │ │ ├── entry-item.component.html
│ │ │ │ ├── entry-item.component.spec.ts
│ │ │ │ └── entry-item.component.ts
│ │ │ ├── interfaces
│ │ │ │ └── exercise-set.ts
│ │ │ ├── list-entries
│ │ │ │ ├── list-entries.component.css
│ │ │ │ ├── list-entries.component.html
│ │ │ │ ├── list-entries.component.spec.ts
│ │ │ │ └── list-entries.component.ts
│ │ │ ├── new-entry-form-reactive
│ │ │ │ ├── custom-validation.ts
│ │ │ │ ├── new-entry-form-reactive.component.css
│ │ │ │ ├── new-entry-form-reactive.component.html
│ │ │ │ ├── new-entry-form-reactive.component.spec.ts
│ │ │ │ └── new-entry-form-reactive.component.ts
│ │ │ ├── new-entry-form-template
│ │ │ │ ├── new-entry-form-template.component.css
│ │ │ │ ├── new-entry-form-template.component.html
│ │ │ │ ├── new-entry-form-template.component.spec.ts
│ │ │ │ └── new-entry-form-template.component.ts
│ │ │ ├── new-item-button
│ │ │ │ ├── new-item-button.component.css
│ │ │ │ ├── new-item-button.component.html
│ │ │ │ ├── new-item-button.component.spec.ts
│ │ │ │ └── new-item-button.component.ts
│ │ │ └── services
│ │ │ │ ├── exercise-sets.service.spec.ts
│ │ │ │ └── exercise-sets.service.ts
│ │ ├── error-page
│ │ │ ├── error-page.component.css
│ │ │ ├── error-page.component.html
│ │ │ ├── error-page.component.spec.ts
│ │ │ └── error-page.component.ts
│ │ ├── home
│ │ │ ├── home-routing.module.ts
│ │ │ ├── home.component.css
│ │ │ ├── home.component.html
│ │ │ ├── home.component.spec.ts
│ │ │ ├── home.component.ts
│ │ │ └── home.module.ts
│ │ └── login
│ │ │ ├── auth.guard.spec.ts
│ │ │ ├── auth.guard.ts
│ │ │ ├── auth.service.spec.ts
│ │ │ ├── auth.service.ts
│ │ │ ├── auth.ts
│ │ │ ├── login-routing.module.ts
│ │ │ ├── login.component.css
│ │ │ ├── login.component.html
│ │ │ ├── login.component.spec.ts
│ │ │ ├── login.component.ts
│ │ │ └── login.module.ts
│ ├── assets
│ │ └── .gitkeep
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ └── styles.css
│ ├── tailwind.config.js
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ └── tsconfig.spec.json
├── ch8
├── gym-diary-backend
│ ├── .eslintrc.js
│ ├── .gitignore
│ ├── .prettierrc
│ ├── README.md
│ ├── nest-cli.json
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── app.controller.spec.ts
│ │ ├── app.controller.ts
│ │ ├── app.module.ts
│ │ ├── app.service.ts
│ │ ├── auth
│ │ │ ├── auth.controller.ts
│ │ │ ├── auth.guard.ts
│ │ │ ├── auth.module.ts
│ │ │ ├── auth.service.spec.ts
│ │ │ ├── auth.service.ts
│ │ │ ├── constants.ts
│ │ │ └── public.decorator.ts
│ │ ├── diary
│ │ │ ├── db
│ │ │ │ └── diary.data.ts
│ │ │ ├── diary.controller.ts
│ │ │ ├── diary.module.ts
│ │ │ ├── dto
│ │ │ │ ├── create-diaries.dto.ts
│ │ │ │ └── get-diaries.dto.ts
│ │ │ ├── exercises.service.ts
│ │ │ ├── interface
│ │ │ │ └── diary.interface.ts
│ │ │ └── repository
│ │ │ │ ├── diary-repository-memory.service.ts
│ │ │ │ └── diary-repository.service.ts
│ │ ├── exercises
│ │ │ ├── db
│ │ │ │ └── exercises.data.ts
│ │ │ ├── dto
│ │ │ │ ├── create-exercises.dto.ts
│ │ │ │ └── get-exercises.dto.ts
│ │ │ ├── exercises.controller.ts
│ │ │ ├── exercises.module.ts
│ │ │ ├── exercises.service.ts
│ │ │ ├── interface
│ │ │ │ └── exercises.interface.ts
│ │ │ └── repository
│ │ │ │ ├── exercises-repository-memory.service.ts
│ │ │ │ └── exercises-repository.service.ts
│ │ ├── main.ts
│ │ ├── users
│ │ │ ├── db
│ │ │ │ └── users.data.ts
│ │ │ ├── dto
│ │ │ │ ├── create-users.dto.ts
│ │ │ │ └── get-users.dto.ts
│ │ │ ├── interface
│ │ │ │ └── users.interface.ts
│ │ │ ├── repository
│ │ │ │ ├── users-repository-memory.service.ts
│ │ │ │ └── users-repository.service.ts
│ │ │ ├── users.module.ts
│ │ │ └── users.service.ts
│ │ └── utils
│ │ │ ├── interfaces
│ │ │ ├── collection.interface.ts
│ │ │ ├── error.interface.ts
│ │ │ └── query.interface.ts
│ │ │ └── utils.ts
│ ├── test
│ │ ├── app.e2e-spec.ts
│ │ └── jest-e2e.json
│ ├── tsconfig.build.json
│ └── tsconfig.json
└── gym-diary
│ ├── .editorconfig
│ ├── .gitignore
│ ├── .vscode
│ ├── extensions.json
│ ├── launch.json
│ └── tasks.json
│ ├── README.md
│ ├── angular.json
│ ├── package-lock.json
│ ├── package.json
│ ├── prettier.config.js
│ ├── src
│ ├── app
│ │ ├── app-routing.module.ts
│ │ ├── app.component.css
│ │ ├── app.component.html
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── app.module.ts
│ │ ├── diary
│ │ │ ├── diary-routing.module.ts
│ │ │ ├── diary.module.ts
│ │ │ ├── diary.resolver.spec.ts
│ │ │ ├── diary.resolver.ts
│ │ │ ├── diary
│ │ │ │ ├── diary.component.css
│ │ │ │ ├── diary.component.html
│ │ │ │ ├── diary.component.spec.ts
│ │ │ │ └── diary.component.ts
│ │ │ ├── entry-item
│ │ │ │ ├── entry-item.component.css
│ │ │ │ ├── entry-item.component.html
│ │ │ │ ├── entry-item.component.spec.ts
│ │ │ │ └── entry-item.component.ts
│ │ │ ├── interfaces
│ │ │ │ └── exercise-set.ts
│ │ │ ├── list-entries
│ │ │ │ ├── list-entries.component.css
│ │ │ │ ├── list-entries.component.html
│ │ │ │ ├── list-entries.component.spec.ts
│ │ │ │ └── list-entries.component.ts
│ │ │ ├── new-entry-form-reactive
│ │ │ │ ├── custom-validation.ts
│ │ │ │ ├── new-entry-form-reactive.component.css
│ │ │ │ ├── new-entry-form-reactive.component.html
│ │ │ │ ├── new-entry-form-reactive.component.spec.ts
│ │ │ │ └── new-entry-form-reactive.component.ts
│ │ │ ├── new-entry-form-template
│ │ │ │ ├── new-entry-form-template.component.css
│ │ │ │ ├── new-entry-form-template.component.html
│ │ │ │ ├── new-entry-form-template.component.spec.ts
│ │ │ │ └── new-entry-form-template.component.ts
│ │ │ ├── new-item-button
│ │ │ │ ├── new-item-button.component.css
│ │ │ │ ├── new-item-button.component.html
│ │ │ │ ├── new-item-button.component.spec.ts
│ │ │ │ └── new-item-button.component.ts
│ │ │ └── services
│ │ │ │ ├── exercise-sets.service.spec.ts
│ │ │ │ └── exercise-sets.service.ts
│ │ ├── error-page
│ │ │ ├── error-page.component.css
│ │ │ ├── error-page.component.html
│ │ │ ├── error-page.component.spec.ts
│ │ │ └── error-page.component.ts
│ │ ├── home
│ │ │ ├── home-routing.module.ts
│ │ │ ├── home.component.css
│ │ │ ├── home.component.html
│ │ │ ├── home.component.spec.ts
│ │ │ ├── home.component.ts
│ │ │ └── home.module.ts
│ │ ├── loading-overlay
│ │ │ ├── load.interceptor.spec.ts
│ │ │ ├── load.interceptor.ts
│ │ │ ├── load.service.spec.ts
│ │ │ ├── load.service.ts
│ │ │ ├── loading-overlay.component.css
│ │ │ ├── loading-overlay.component.html
│ │ │ ├── loading-overlay.component.spec.ts
│ │ │ └── loading-overlay.component.ts
│ │ ├── login
│ │ │ ├── auth.guard.spec.ts
│ │ │ ├── auth.guard.ts
│ │ │ ├── auth.interceptor.spec.ts
│ │ │ ├── auth.interceptor.ts
│ │ │ ├── auth.service.spec.ts
│ │ │ ├── auth.service.ts
│ │ │ ├── auth.ts
│ │ │ ├── login-routing.module.ts
│ │ │ ├── login.component.css
│ │ │ ├── login.component.html
│ │ │ ├── login.component.spec.ts
│ │ │ ├── login.component.ts
│ │ │ └── login.module.ts
│ │ ├── notification
│ │ │ ├── notification.interceptor.spec.ts
│ │ │ └── notification.interceptor.ts
│ │ ├── shared
│ │ │ ├── host.interceptor.spec.ts
│ │ │ └── host.interceptor.ts
│ │ └── telemetry
│ │ │ ├── telemetry.interceptor.spec.ts
│ │ │ └── telemetry.interceptor.ts
│ ├── assets
│ │ └── .gitkeep
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ └── styles.css
│ ├── tailwind.config.js
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ └── tsconfig.spec.json
└── ch9
├── gym-diary-backend
├── .eslintrc.js
├── .gitignore
├── .prettierrc
├── README.md
├── nest-cli.json
├── package-lock.json
├── package.json
├── src
│ ├── app.controller.spec.ts
│ ├── app.controller.ts
│ ├── app.module.ts
│ ├── app.service.ts
│ ├── auth
│ │ ├── auth.controller.ts
│ │ ├── auth.guard.ts
│ │ ├── auth.module.ts
│ │ ├── auth.service.spec.ts
│ │ ├── auth.service.ts
│ │ ├── constants.ts
│ │ └── public.decorator.ts
│ ├── diary
│ │ ├── db
│ │ │ └── diary.data.ts
│ │ ├── diary.controller.ts
│ │ ├── diary.module.ts
│ │ ├── dto
│ │ │ ├── create-diaries.dto.ts
│ │ │ └── get-diaries.dto.ts
│ │ ├── exercises.service.ts
│ │ ├── interface
│ │ │ └── diary.interface.ts
│ │ └── repository
│ │ │ ├── diary-repository-memory.service.ts
│ │ │ └── diary-repository.service.ts
│ ├── exercises
│ │ ├── db
│ │ │ └── exercises.data.ts
│ │ ├── dto
│ │ │ ├── create-exercises.dto.ts
│ │ │ └── get-exercises.dto.ts
│ │ ├── exercises.controller.ts
│ │ ├── exercises.module.ts
│ │ ├── exercises.service.ts
│ │ ├── interface
│ │ │ └── exercises.interface.ts
│ │ └── repository
│ │ │ ├── exercises-repository-memory.service.ts
│ │ │ └── exercises-repository.service.ts
│ ├── main.ts
│ ├── users
│ │ ├── db
│ │ │ └── users.data.ts
│ │ ├── dto
│ │ │ ├── create-users.dto.ts
│ │ │ └── get-users.dto.ts
│ │ ├── interface
│ │ │ └── users.interface.ts
│ │ ├── repository
│ │ │ ├── users-repository-memory.service.ts
│ │ │ └── users-repository.service.ts
│ │ ├── users.module.ts
│ │ └── users.service.ts
│ └── utils
│ │ ├── interfaces
│ │ ├── collection.interface.ts
│ │ ├── error.interface.ts
│ │ └── query.interface.ts
│ │ └── utils.ts
├── test
│ ├── app.e2e-spec.ts
│ └── jest-e2e.json
├── tsconfig.build.json
└── tsconfig.json
└── gym-diary
├── .editorconfig
├── .gitignore
├── .vscode
├── extensions.json
├── launch.json
└── tasks.json
├── README.md
├── angular.json
├── package-lock.json
├── package.json
├── prettier.config.js
├── src
├── app
│ ├── app-routing.module.ts
│ ├── app.component.css
│ ├── app.component.html
│ ├── app.component.spec.ts
│ ├── app.component.ts
│ ├── app.module.ts
│ ├── diary
│ │ ├── diary-routing.module.ts
│ │ ├── diary.module.ts
│ │ ├── diary.resolver.spec.ts
│ │ ├── diary.resolver.ts
│ │ ├── diary
│ │ │ ├── diary.component.css
│ │ │ ├── diary.component.html
│ │ │ ├── diary.component.spec.ts
│ │ │ └── diary.component.ts
│ │ ├── entry-item
│ │ │ ├── entry-item.component.css
│ │ │ ├── entry-item.component.html
│ │ │ ├── entry-item.component.spec.ts
│ │ │ └── entry-item.component.ts
│ │ ├── interfaces
│ │ │ ├── exercise-set.ts
│ │ │ └── exercise.ts
│ │ ├── list-entries
│ │ │ ├── list-entries.component.css
│ │ │ ├── list-entries.component.html
│ │ │ ├── list-entries.component.spec.ts
│ │ │ └── list-entries.component.ts
│ │ ├── new-entry-form-reactive
│ │ │ ├── custom-validation.ts
│ │ │ ├── new-entry-form-reactive.component.css
│ │ │ ├── new-entry-form-reactive.component.html
│ │ │ ├── new-entry-form-reactive.component.spec.ts
│ │ │ └── new-entry-form-reactive.component.ts
│ │ ├── new-entry-form-template
│ │ │ ├── new-entry-form-template.component.css
│ │ │ ├── new-entry-form-template.component.html
│ │ │ ├── new-entry-form-template.component.spec.ts
│ │ │ └── new-entry-form-template.component.ts
│ │ ├── new-item-button
│ │ │ ├── new-item-button.component.css
│ │ │ ├── new-item-button.component.html
│ │ │ ├── new-item-button.component.spec.ts
│ │ │ └── new-item-button.component.ts
│ │ └── services
│ │ │ ├── exercise-sets.service.spec.ts
│ │ │ ├── exercise-sets.service.ts
│ │ │ ├── exercises.service.spec.ts
│ │ │ └── exercises.service.ts
│ ├── error-page
│ │ ├── error-page.component.css
│ │ ├── error-page.component.html
│ │ ├── error-page.component.spec.ts
│ │ └── error-page.component.ts
│ ├── home
│ │ ├── home-routing.module.ts
│ │ ├── home.component.css
│ │ ├── home.component.html
│ │ ├── home.component.spec.ts
│ │ ├── home.component.ts
│ │ └── home.module.ts
│ ├── loading-overlay
│ │ ├── load.interceptor.spec.ts
│ │ ├── load.interceptor.ts
│ │ ├── load.service.spec.ts
│ │ ├── load.service.ts
│ │ ├── loading-overlay.component.css
│ │ ├── loading-overlay.component.html
│ │ ├── loading-overlay.component.spec.ts
│ │ └── loading-overlay.component.ts
│ ├── login
│ │ ├── auth.guard.spec.ts
│ │ ├── auth.guard.ts
│ │ ├── auth.interceptor.spec.ts
│ │ ├── auth.interceptor.ts
│ │ ├── auth.service.spec.ts
│ │ ├── auth.service.ts
│ │ ├── auth.ts
│ │ ├── login-routing.module.ts
│ │ ├── login.component.css
│ │ ├── login.component.html
│ │ ├── login.component.spec.ts
│ │ ├── login.component.ts
│ │ └── login.module.ts
│ ├── notification
│ │ ├── notification.interceptor.spec.ts
│ │ └── notification.interceptor.ts
│ ├── shared
│ │ ├── host.interceptor.spec.ts
│ │ └── host.interceptor.ts
│ └── telemetry
│ │ ├── telemetry.interceptor.spec.ts
│ │ └── telemetry.interceptor.ts
├── assets
│ └── .gitkeep
├── favicon.ico
├── index.html
├── main.ts
└── styles.css
├── tailwind.config.js
├── tsconfig.app.json
├── tsconfig.json
└── tsconfig.spec.json
/ch1/angular-start/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/ch1/angular-start/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3 | "recommendations": ["angular.ng-template"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch1/angular-start/src/app/about/about.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch1/angular-start/src/app/about/about.component.css
--------------------------------------------------------------------------------
/ch1/angular-start/src/app/about/about.component.html:
--------------------------------------------------------------------------------
1 |
about works!
2 |
--------------------------------------------------------------------------------
/ch1/angular-start/src/app/about/about.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-about',
5 | templateUrl: './about.component.html',
6 | styleUrls: ['./about.component.css']
7 | })
8 | export class AboutComponent {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/ch1/angular-start/src/app/app-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { RouterModule, Routes } from '@angular/router';
3 |
4 | const routes: Routes = [];
5 |
6 | @NgModule({
7 | imports: [RouterModule.forRoot(routes)],
8 | exports: [RouterModule]
9 | })
10 | export class AppRoutingModule { }
11 |
--------------------------------------------------------------------------------
/ch1/angular-start/src/app/app.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch1/angular-start/src/app/app.component.css
--------------------------------------------------------------------------------
/ch1/angular-start/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-root',
5 | templateUrl: './app.component.html',
6 | styleUrls: ['./app.component.css']
7 | })
8 | export class AppComponent {
9 | title = 'angular-start';
10 | }
11 |
--------------------------------------------------------------------------------
/ch1/angular-start/src/app/home/home.component.css:
--------------------------------------------------------------------------------
1 | .sidenav-container {
2 | height: 100%;
3 | }
4 |
5 | .sidenav {
6 | width: 200px;
7 | }
8 |
9 | .sidenav .mat-toolbar {
10 | background: inherit;
11 | }
12 |
13 | .mat-toolbar.mat-primary {
14 | position: sticky;
15 | top: 0;
16 | z-index: 1;
17 | }
18 |
--------------------------------------------------------------------------------
/ch1/angular-start/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch1/angular-start/src/assets/.gitkeep
--------------------------------------------------------------------------------
/ch1/angular-start/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch1/angular-start/src/favicon.ico
--------------------------------------------------------------------------------
/ch1/angular-start/src/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
2 |
3 | import { AppModule } from './app/app.module';
4 |
5 |
6 | platformBrowserDynamic().bootstrapModule(AppModule)
7 | .catch(err => console.error(err));
8 |
--------------------------------------------------------------------------------
/ch1/angular-start/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 |
3 | html, body { height: 100%; }
4 | body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
5 |
--------------------------------------------------------------------------------
/ch1/angular-start/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts"
10 | ],
11 | "include": [
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch1/angular-start/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "include": [
11 | "src/**/*.spec.ts",
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch10/gym-diary-backend/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all"
4 | }
--------------------------------------------------------------------------------
/ch10/gym-diary-backend/nest-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/nest-cli",
3 | "collection": "@nestjs/schematics",
4 | "sourceRoot": "src",
5 | "compilerOptions": {
6 | "deleteOutDir": true
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch10/gym-diary-backend/src/app.controller.ts:
--------------------------------------------------------------------------------
1 | import { Controller } from '@nestjs/common';
2 |
3 | @Controller()
4 | export class AppController {}
5 |
--------------------------------------------------------------------------------
/ch10/gym-diary-backend/src/app.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 |
3 | @Injectable()
4 | export class AppService {
5 | getHello(): string {
6 | return 'Hello World!';
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch10/gym-diary-backend/src/auth/constants.ts:
--------------------------------------------------------------------------------
1 | export const jwtConstants = {
2 | secret:
3 | 'DO NOT USE THIS VALUE. INSTEAD, CREATE A COMPLEX SECRET AND KEEP IT SAFE OUTSIDE OF THE SOURCE CODE.',
4 | };
5 |
--------------------------------------------------------------------------------
/ch10/gym-diary-backend/src/auth/public.decorator.ts:
--------------------------------------------------------------------------------
1 | import { SetMetadata } from '@nestjs/common';
2 |
3 | export const IS_PUBLIC_KEY = 'isPublic';
4 | export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
5 |
--------------------------------------------------------------------------------
/ch10/gym-diary-backend/src/diary/interface/diary.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Diaries = Array;
4 | export interface Diary extends Item {
5 | date?: string;
6 | exercise?: string;
7 | sets?: number;
8 | reps?: number;
9 | }
10 |
11 | export interface DiariesAPI extends Collection {
12 | items: Diaries;
13 | }
14 |
--------------------------------------------------------------------------------
/ch10/gym-diary-backend/src/exercises/dto/create-exercises.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiPropertyOptional } from '@nestjs/swagger';
2 | import { Exercise } from '../interface/exercises.interface';
3 |
4 | export class CreateExercisesDto implements Exercise {
5 | @ApiPropertyOptional()
6 | id: string;
7 |
8 | @ApiPropertyOptional()
9 | description: string;
10 | }
11 |
--------------------------------------------------------------------------------
/ch10/gym-diary-backend/src/exercises/interface/exercises.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Exercises = Array;
4 | export interface Exercise extends Item {
5 | description?: string;
6 | }
7 |
8 | export interface ExercisesAPI extends Collection {
9 | items: Exercises;
10 | }
11 |
--------------------------------------------------------------------------------
/ch10/gym-diary-backend/src/users/db/users.data.ts:
--------------------------------------------------------------------------------
1 | import { Users } from '../interface/users.interface';
2 |
3 | export const users: Users = [
4 | {
5 | id: '1',
6 | username: 'mario',
7 | password: '1234',
8 | name: 'mario',
9 | },
10 | {
11 | id: '2',
12 | username: 'gabriel',
13 | password: '1234',
14 | name: 'gabriel',
15 | },
16 | ];
17 |
--------------------------------------------------------------------------------
/ch10/gym-diary-backend/src/users/dto/get-users.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { UsersAPI } from '../interface/users.interface';
3 | import { CreateUsersDto } from './create-users.dto';
4 |
5 | export class GetUsersDTO implements UsersAPI {
6 | @ApiProperty()
7 | hasNext: boolean;
8 |
9 | @ApiProperty({ type: () => [CreateUsersDto] })
10 | items: Array;
11 | }
12 |
--------------------------------------------------------------------------------
/ch10/gym-diary-backend/src/users/interface/users.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Users = Array;
4 | export interface User extends Item {
5 | username?: string;
6 | password?: string;
7 | name?: string;
8 | }
9 |
10 | export interface UsersAPI extends Collection {
11 | items: Users;
12 | }
13 |
--------------------------------------------------------------------------------
/ch10/gym-diary-backend/src/utils/interfaces/collection.interface.ts:
--------------------------------------------------------------------------------
1 | export interface Collection {
2 | hasNext?: boolean;
3 | items: Items;
4 | }
5 |
6 | export interface Item {
7 | id?: string;
8 | }
9 |
10 | export type Items = Array- ;
11 |
--------------------------------------------------------------------------------
/ch10/gym-diary-backend/src/utils/interfaces/error.interface.ts:
--------------------------------------------------------------------------------
1 | export interface Error {
2 | code: 'string';
3 | message: 'string';
4 | detailedMessage: 'string';
5 | helpUrl: 'string';
6 | details: 'string';
7 | }
8 |
--------------------------------------------------------------------------------
/ch10/gym-diary-backend/src/utils/interfaces/query.interface.ts:
--------------------------------------------------------------------------------
1 | export interface QueryApi {
2 | search?: string;
3 | filter?: string;
4 | page?: string;
5 | pageSize?: string;
6 | }
7 |
8 | export interface ParamQueryId {
9 | id?: string;
10 | }
11 |
--------------------------------------------------------------------------------
/ch10/gym-diary-backend/test/jest-e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "moduleFileExtensions": ["js", "json", "ts"],
3 | "rootDir": ".",
4 | "testEnvironment": "node",
5 | "testRegex": ".e2e-spec.ts$",
6 | "transform": {
7 | "^.+\\.(t|j)s$": "ts-jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ch10/gym-diary-backend/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch10/gym-diary/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/ch10/gym-diary/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3 | "recommendations": ["angular.ng-template"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch10/gym-diary/cypress.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'cypress'
2 |
3 | export default defineConfig({
4 |
5 | e2e: {
6 | 'baseUrl': 'http://localhost:4200'
7 | },
8 |
9 |
10 | component: {
11 | devServer: {
12 | framework: 'angular',
13 | bundler: 'webpack',
14 | },
15 | specPattern: '**/*.cy.ts'
16 | }
17 |
18 | })
--------------------------------------------------------------------------------
/ch10/gym-diary/cypress/e2e/login.cy.ts:
--------------------------------------------------------------------------------
1 | describe('Login Page:', () => {
2 | it('should login to the diary with the correct credentials.', () => {
3 | cy.visit('/');
4 | cy.get('#username').type('mario');
5 | cy.get('#password').type('1234');
6 | cy.get('[data-cy="submit"]').click();
7 | cy.contains('Workout diary');
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/ch10/gym-diary/cypress/fixtures/example.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Using fixtures to represent data",
3 | "email": "hello@cypress.io"
4 | }
5 |
--------------------------------------------------------------------------------
/ch10/gym-diary/cypress/support/component-index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Components App
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/ch10/gym-diary/cypress/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "include": ["**/*.ts"],
4 | "compilerOptions": {
5 | "sourceMap": false,
6 | "types": ["cypress"]
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch10/gym-diary/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [require('prettier-plugin-tailwindcss')],
3 | tailwindConfig: './tailwind.config.js',
4 | }
--------------------------------------------------------------------------------
/ch10/gym-diary/src/app/app.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch10/gym-diary/src/app/app.component.css
--------------------------------------------------------------------------------
/ch10/gym-diary/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/ch10/gym-diary/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, inject } from '@angular/core';
2 | import { LoadService } from './loading-overlay/load.service';
3 |
4 | @Component({
5 | selector: 'app-root',
6 | templateUrl: './app.component.html',
7 | styleUrls: ['./app.component.css'],
8 | })
9 | export class AppComponent {
10 | loadService = inject(LoadService);
11 | title = 'gym-diary';
12 | }
13 |
--------------------------------------------------------------------------------
/ch10/gym-diary/src/app/diary/diary/diary.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch10/gym-diary/src/app/diary/diary/diary.component.css
--------------------------------------------------------------------------------
/ch10/gym-diary/src/app/diary/entry-item/entry-item.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch10/gym-diary/src/app/diary/entry-item/entry-item.component.css
--------------------------------------------------------------------------------
/ch10/gym-diary/src/app/diary/interfaces/exercise-set.ts:
--------------------------------------------------------------------------------
1 | export interface ExerciseSet {
2 | id?: string;
3 | date: Date;
4 | exercise: string;
5 | sets: number;
6 | reps: number;
7 | }
8 |
9 | export type ExerciseSetList = Array;
10 |
11 | export interface ExerciseSetListAPI {
12 | hasNext: boolean;
13 | items: ExerciseSetList;
14 | }
15 |
--------------------------------------------------------------------------------
/ch10/gym-diary/src/app/diary/interfaces/exercise.ts:
--------------------------------------------------------------------------------
1 | export interface Exercise {
2 | id?: string;
3 | description: string;
4 | }
5 |
6 | export type ExerciseList = Array;
7 |
8 | export interface ExerciseListAPI {
9 | hasNext: boolean;
10 | items: ExerciseList;
11 | }
12 |
--------------------------------------------------------------------------------
/ch10/gym-diary/src/app/diary/list-entries/list-entries.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch10/gym-diary/src/app/diary/list-entries/list-entries.component.css
--------------------------------------------------------------------------------
/ch10/gym-diary/src/app/diary/new-entry-form-reactive/new-entry-form-reactive.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch10/gym-diary/src/app/diary/new-entry-form-reactive/new-entry-form-reactive.component.css
--------------------------------------------------------------------------------
/ch10/gym-diary/src/app/diary/new-entry-form-template/new-entry-form-template.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch10/gym-diary/src/app/diary/new-entry-form-template/new-entry-form-template.component.css
--------------------------------------------------------------------------------
/ch10/gym-diary/src/app/diary/new-item-button/new-item-button.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch10/gym-diary/src/app/diary/new-item-button/new-item-button.component.css
--------------------------------------------------------------------------------
/ch10/gym-diary/src/app/diary/new-item-button/new-item-button.component.html:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/ch10/gym-diary/src/app/error-page/error-page.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch10/gym-diary/src/app/error-page/error-page.component.css
--------------------------------------------------------------------------------
/ch10/gym-diary/src/app/error-page/error-page.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-error-page',
5 | templateUrl: './error-page.component.html',
6 | styleUrls: ['./error-page.component.css']
7 | })
8 | export class ErrorPageComponent {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/ch10/gym-diary/src/app/home/home.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch10/gym-diary/src/app/home/home.component.css
--------------------------------------------------------------------------------
/ch10/gym-diary/src/app/home/home.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 |
4 | import { HomeRoutingModule } from './home-routing.module';
5 | import { HomeComponent } from './home.component';
6 |
7 | @NgModule({
8 | declarations: [HomeComponent],
9 | imports: [CommonModule, HomeRoutingModule],
10 | })
11 | export class HomeModule {}
12 |
--------------------------------------------------------------------------------
/ch10/gym-diary/src/app/loading-overlay/loading-overlay.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch10/gym-diary/src/app/loading-overlay/loading-overlay.component.css
--------------------------------------------------------------------------------
/ch10/gym-diary/src/app/loading-overlay/loading-overlay.component.html:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/ch10/gym-diary/src/app/loading-overlay/loading-overlay.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-loading-overlay',
5 | templateUrl: './loading-overlay.component.html',
6 | styleUrls: ['./loading-overlay.component.css']
7 | })
8 | export class LoadingOverlayComponent {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/ch10/gym-diary/src/app/login/auth.ts:
--------------------------------------------------------------------------------
1 | export interface LoginForm {
2 | username: string;
3 | password: string;
4 | }
5 |
6 | export interface Token {
7 | access_token: string;
8 | }
9 |
--------------------------------------------------------------------------------
/ch10/gym-diary/src/app/login/login.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch10/gym-diary/src/app/login/login.component.css
--------------------------------------------------------------------------------
/ch10/gym-diary/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch10/gym-diary/src/assets/.gitkeep
--------------------------------------------------------------------------------
/ch10/gym-diary/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch10/gym-diary/src/favicon.ico
--------------------------------------------------------------------------------
/ch10/gym-diary/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | GymDiary
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch10/gym-diary/src/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
2 |
3 | import { AppModule } from './app/app.module';
4 |
5 |
6 | platformBrowserDynamic().bootstrapModule(AppModule)
7 | .catch(err => console.error(err));
8 |
--------------------------------------------------------------------------------
/ch10/gym-diary/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 | @tailwind base;
3 | @tailwind components;
4 | @tailwind utilities;
--------------------------------------------------------------------------------
/ch10/gym-diary/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./src/**/*.{html,ts}",
5 | ],
6 | theme: {
7 | extend: {},
8 | },
9 | plugins: [],
10 | }
11 |
--------------------------------------------------------------------------------
/ch10/gym-diary/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts"
10 | ],
11 | "include": [
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch10/gym-diary/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "include": [
11 | "src/**/*.spec.ts",
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch11/gym-diary-backend/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all"
4 | }
--------------------------------------------------------------------------------
/ch11/gym-diary-backend/nest-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/nest-cli",
3 | "collection": "@nestjs/schematics",
4 | "sourceRoot": "src",
5 | "compilerOptions": {
6 | "deleteOutDir": true
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch11/gym-diary-backend/src/app.controller.ts:
--------------------------------------------------------------------------------
1 | import { Controller } from '@nestjs/common';
2 |
3 | @Controller()
4 | export class AppController {}
5 |
--------------------------------------------------------------------------------
/ch11/gym-diary-backend/src/app.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 |
3 | @Injectable()
4 | export class AppService {
5 | getHello(): string {
6 | return 'Hello World!';
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch11/gym-diary-backend/src/auth/constants.ts:
--------------------------------------------------------------------------------
1 | export const jwtConstants = {
2 | secret:
3 | 'DO NOT USE THIS VALUE. INSTEAD, CREATE A COMPLEX SECRET AND KEEP IT SAFE OUTSIDE OF THE SOURCE CODE.',
4 | };
5 |
--------------------------------------------------------------------------------
/ch11/gym-diary-backend/src/auth/public.decorator.ts:
--------------------------------------------------------------------------------
1 | import { SetMetadata } from '@nestjs/common';
2 |
3 | export const IS_PUBLIC_KEY = 'isPublic';
4 | export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
5 |
--------------------------------------------------------------------------------
/ch11/gym-diary-backend/src/diary/interface/diary.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Diaries = Array;
4 | export interface Diary extends Item {
5 | date?: string;
6 | exercise?: string;
7 | sets?: number;
8 | reps?: number;
9 | }
10 |
11 | export interface DiariesAPI extends Collection {
12 | items: Diaries;
13 | }
14 |
--------------------------------------------------------------------------------
/ch11/gym-diary-backend/src/exercises/dto/create-exercises.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiPropertyOptional } from '@nestjs/swagger';
2 | import { Exercise } from '../interface/exercises.interface';
3 |
4 | export class CreateExercisesDto implements Exercise {
5 | @ApiPropertyOptional()
6 | id: string;
7 |
8 | @ApiPropertyOptional()
9 | description: string;
10 | }
11 |
--------------------------------------------------------------------------------
/ch11/gym-diary-backend/src/exercises/interface/exercises.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Exercises = Array;
4 | export interface Exercise extends Item {
5 | description?: string;
6 | }
7 |
8 | export interface ExercisesAPI extends Collection {
9 | items: Exercises;
10 | }
11 |
--------------------------------------------------------------------------------
/ch11/gym-diary-backend/src/users/db/users.data.ts:
--------------------------------------------------------------------------------
1 | import { Users } from '../interface/users.interface';
2 |
3 | export const users: Users = [
4 | {
5 | id: '1',
6 | username: 'mario',
7 | password: '1234',
8 | name: 'mario',
9 | },
10 | {
11 | id: '2',
12 | username: 'gabriel',
13 | password: '1234',
14 | name: 'gabriel',
15 | },
16 | ];
17 |
--------------------------------------------------------------------------------
/ch11/gym-diary-backend/src/users/dto/get-users.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { UsersAPI } from '../interface/users.interface';
3 | import { CreateUsersDto } from './create-users.dto';
4 |
5 | export class GetUsersDTO implements UsersAPI {
6 | @ApiProperty()
7 | hasNext: boolean;
8 |
9 | @ApiProperty({ type: () => [CreateUsersDto] })
10 | items: Array;
11 | }
12 |
--------------------------------------------------------------------------------
/ch11/gym-diary-backend/src/users/interface/users.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Users = Array;
4 | export interface User extends Item {
5 | username?: string;
6 | password?: string;
7 | name?: string;
8 | }
9 |
10 | export interface UsersAPI extends Collection {
11 | items: Users;
12 | }
13 |
--------------------------------------------------------------------------------
/ch11/gym-diary-backend/src/utils/interfaces/collection.interface.ts:
--------------------------------------------------------------------------------
1 | export interface Collection {
2 | hasNext?: boolean;
3 | items: Items;
4 | }
5 |
6 | export interface Item {
7 | id?: string;
8 | }
9 |
10 | export type Items = Array
- ;
11 |
--------------------------------------------------------------------------------
/ch11/gym-diary-backend/src/utils/interfaces/error.interface.ts:
--------------------------------------------------------------------------------
1 | export interface Error {
2 | code: 'string';
3 | message: 'string';
4 | detailedMessage: 'string';
5 | helpUrl: 'string';
6 | details: 'string';
7 | }
8 |
--------------------------------------------------------------------------------
/ch11/gym-diary-backend/src/utils/interfaces/query.interface.ts:
--------------------------------------------------------------------------------
1 | export interface QueryApi {
2 | search?: string;
3 | filter?: string;
4 | page?: string;
5 | pageSize?: string;
6 | }
7 |
8 | export interface ParamQueryId {
9 | id?: string;
10 | }
11 |
--------------------------------------------------------------------------------
/ch11/gym-diary-backend/test/jest-e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "moduleFileExtensions": ["js", "json", "ts"],
3 | "rootDir": ".",
4 | "testEnvironment": "node",
5 | "testRegex": ".e2e-spec.ts$",
6 | "transform": {
7 | "^.+\\.(t|j)s$": "ts-jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ch11/gym-diary-backend/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch11/gym-diary/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/ch11/gym-diary/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3 | "recommendations": ["angular.ng-template"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch11/gym-diary/cypress.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'cypress'
2 |
3 | export default defineConfig({
4 |
5 | e2e: {
6 | 'baseUrl': 'http://localhost:4200'
7 | },
8 |
9 |
10 | component: {
11 | devServer: {
12 | framework: 'angular',
13 | bundler: 'webpack',
14 | },
15 | specPattern: '**/*.cy.ts'
16 | }
17 |
18 | })
--------------------------------------------------------------------------------
/ch11/gym-diary/cypress/e2e/login.cy.ts:
--------------------------------------------------------------------------------
1 | describe('Login Page:', () => {
2 | it('should login to the diary with the correct credentials.', () => {
3 | cy.visit('/');
4 | cy.get('#username').type('mario');
5 | cy.get('#password').type('1234');
6 | cy.get('[data-cy="submit"]').click();
7 | cy.contains('Workout diary');
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/ch11/gym-diary/cypress/fixtures/example.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Using fixtures to represent data",
3 | "email": "hello@cypress.io"
4 | }
5 |
--------------------------------------------------------------------------------
/ch11/gym-diary/cypress/support/component-index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Components App
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/ch11/gym-diary/cypress/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "include": ["**/*.ts"],
4 | "compilerOptions": {
5 | "sourceMap": false,
6 | "types": ["cypress"]
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch11/gym-diary/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [require('prettier-plugin-tailwindcss')],
3 | tailwindConfig: './tailwind.config.js',
4 | }
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/app.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch11/gym-diary/src/app/app.component.css
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, inject } from '@angular/core';
2 | import { LoadService } from './loading-overlay/load.service';
3 |
4 | @Component({
5 | selector: 'app-root',
6 | templateUrl: './app.component.html',
7 | styleUrls: ['./app.component.css'],
8 | })
9 | export class AppComponent {
10 | loadService = inject(LoadService);
11 | title = 'gym-diary';
12 | }
13 |
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/diary/diary/diary.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch11/gym-diary/src/app/diary/diary/diary.component.css
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/diary/entry-item/entry-item.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch11/gym-diary/src/app/diary/entry-item/entry-item.component.css
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/diary/interfaces/exercise-set.ts:
--------------------------------------------------------------------------------
1 | export interface ExerciseSet {
2 | id?: string;
3 | date: Date;
4 | exercise: string;
5 | sets: number;
6 | reps: number;
7 | }
8 |
9 | export type ExerciseSetList = Array;
10 |
11 | export interface ExerciseSetListAPI {
12 | hasNext: boolean;
13 | items: ExerciseSetList;
14 | }
15 |
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/diary/interfaces/exercise.ts:
--------------------------------------------------------------------------------
1 | export interface Exercise {
2 | id?: string;
3 | description: string;
4 | }
5 |
6 | export type ExerciseList = Array;
7 |
8 | export interface ExerciseListAPI {
9 | hasNext: boolean;
10 | items: ExerciseList;
11 | }
12 |
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/diary/list-entries/list-entries.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch11/gym-diary/src/app/diary/list-entries/list-entries.component.css
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/diary/new-entry-form-reactive/new-entry-form-reactive.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch11/gym-diary/src/app/diary/new-entry-form-reactive/new-entry-form-reactive.component.css
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/diary/new-entry-form-template/new-entry-form-template.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch11/gym-diary/src/app/diary/new-entry-form-template/new-entry-form-template.component.css
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/diary/new-item-button/new-item-button.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch11/gym-diary/src/app/diary/new-item-button/new-item-button.component.css
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/diary/new-item-button/new-item-button.component.html:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/error-page/error-page.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch11/gym-diary/src/app/error-page/error-page.component.css
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/error-page/error-page.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-error-page',
5 | templateUrl: './error-page.component.html',
6 | styleUrls: ['./error-page.component.css']
7 | })
8 | export class ErrorPageComponent {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/exercise/exercise/exercise.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch11/gym-diary/src/app/exercise/exercise/exercise.component.css
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/exercise/exercise/exercise.component.cy.ts:
--------------------------------------------------------------------------------
1 | import { ExerciseComponent } from './exercise.component'
2 |
3 | describe('ExerciseComponent', () => {
4 | it('should mount', () => {
5 | cy.mount(ExerciseComponent)
6 | })
7 | })
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/exercise/exercise/exercise.component.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/exercise/exercise/exercise.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-exercise',
5 | templateUrl: './exercise.component.html',
6 | styleUrls: ['./exercise.component.css'],
7 | })
8 | export class ExerciseComponent {
9 | elementUrl = 'http://localhost:8080/main.js';
10 | }
11 |
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/home/home.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch11/gym-diary/src/app/home/home.component.css
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/home/home.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 |
4 | import { HomeRoutingModule } from './home-routing.module';
5 | import { HomeComponent } from './home.component';
6 |
7 | @NgModule({
8 | declarations: [HomeComponent],
9 | imports: [CommonModule, HomeRoutingModule],
10 | })
11 | export class HomeModule {}
12 |
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/loading-overlay/loading-overlay.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch11/gym-diary/src/app/loading-overlay/loading-overlay.component.css
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/loading-overlay/loading-overlay.component.html:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/loading-overlay/loading-overlay.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-loading-overlay',
5 | templateUrl: './loading-overlay.component.html',
6 | styleUrls: ['./loading-overlay.component.css']
7 | })
8 | export class LoadingOverlayComponent {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/login/auth.ts:
--------------------------------------------------------------------------------
1 | export interface LoginForm {
2 | username: string;
3 | password: string;
4 | }
5 |
6 | export interface Token {
7 | access_token: string;
8 | }
9 |
--------------------------------------------------------------------------------
/ch11/gym-diary/src/app/login/login.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch11/gym-diary/src/app/login/login.component.css
--------------------------------------------------------------------------------
/ch11/gym-diary/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch11/gym-diary/src/assets/.gitkeep
--------------------------------------------------------------------------------
/ch11/gym-diary/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch11/gym-diary/src/favicon.ico
--------------------------------------------------------------------------------
/ch11/gym-diary/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | GymDiary
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch11/gym-diary/src/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
2 |
3 | import { AppModule } from './app/app.module';
4 |
5 |
6 | platformBrowserDynamic().bootstrapModule(AppModule)
7 | .catch(err => console.error(err));
8 |
--------------------------------------------------------------------------------
/ch11/gym-diary/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 | @tailwind base;
3 | @tailwind components;
4 | @tailwind utilities;
--------------------------------------------------------------------------------
/ch11/gym-diary/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./src/**/*.{html,ts}",
5 | ],
6 | theme: {
7 | extend: {},
8 | },
9 | plugins: [],
10 | }
11 |
--------------------------------------------------------------------------------
/ch11/gym-diary/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts"
10 | ],
11 | "include": [
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch11/gym-diary/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "include": [
11 | "src/**/*.spec.ts",
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch11/gym_exercises/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/ch11/gym_exercises/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3 | "recommendations": ["angular.ng-template"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch11/gym_exercises/src/app/app.component.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
--------------------------------------------------------------------------------
/ch11/gym_exercises/src/app/app.config.ts:
--------------------------------------------------------------------------------
1 | import { ApplicationConfig } from '@angular/core';
2 | import { provideHttpClient } from '@angular/common/http';
3 |
4 | export const appConfig: ApplicationConfig = {
5 | providers: [provideHttpClient()],
6 | };
7 |
--------------------------------------------------------------------------------
/ch11/gym_exercises/src/app/exercise.ts:
--------------------------------------------------------------------------------
1 | export interface Exercise {
2 | id?: string;
3 | description: string;
4 | }
5 |
6 | export type ExerciseList = Array;
7 |
8 | export interface ExerciseListAPI {
9 | hasNext: boolean;
10 | items: ExerciseList;
11 | }
12 |
--------------------------------------------------------------------------------
/ch11/gym_exercises/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch11/gym_exercises/src/assets/.gitkeep
--------------------------------------------------------------------------------
/ch11/gym_exercises/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch11/gym_exercises/src/favicon.ico
--------------------------------------------------------------------------------
/ch11/gym_exercises/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | GymExercises
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch11/gym_exercises/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 | /*@tailwind base;
3 | @tailwind components;
4 | @tailwind utilities;*/
--------------------------------------------------------------------------------
/ch11/gym_exercises/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./src/**/*.{html,ts}",
5 | ],
6 | theme: {
7 | extend: {},
8 | },
9 | plugins: [],
10 | }
11 |
--------------------------------------------------------------------------------
/ch11/gym_exercises/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts"
10 | ],
11 | "include": [
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch11/gym_exercises/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "include": [
11 | "src/**/*.spec.ts",
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/.dockerignore:
--------------------------------------------------------------------------------
1 | Dockerfile
2 | .dockerignore
3 | node_modules
4 | npm-debug.log
5 | dist
6 | .env
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/.env.production:
--------------------------------------------------------------------------------
1 | NODE_ENV='production'
2 | PORT=80
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/.funcignore:
--------------------------------------------------------------------------------
1 | *.js.map
2 | *.ts
3 | .git*
4 | .vscode
5 | local.settings.json
6 | test
7 | tsconfig.json
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all"
4 | }
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "ms-azuretools.vscode-azurefunctions"
4 | ]
5 | }
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Attach to Node Functions",
6 | "type": "node",
7 | "request": "attach",
8 | "port": 9229,
9 | "preLaunchTask": "func: host start"
10 | }
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "azureFunctions.deploySubpath": ".",
3 | "azureFunctions.postDeployTask": "npm install (functions)",
4 | "azureFunctions.projectLanguage": "TypeScript",
5 | "azureFunctions.projectRuntime": "~4",
6 | "debug.internalConsoleOptions": "neverOpen",
7 | "azureFunctions.preDeployTask": "npm prune (functions)"
8 | }
9 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:latest
2 |
3 | WORKDIR /usr/src/api
4 |
5 | COPY . .
6 |
7 | COPY ./.env.production ./.env
8 |
9 | RUN npm install --quiet --no-optional --no-fund --loglevel=error
10 |
11 | RUN npm run build
12 |
13 | EXPOSE 80
14 |
15 | CMD [ "npm" ,"run", "start:prod" ]
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/host.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0"
3 | }
4 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/local.settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "IsEncrypted": false,
3 | "Values": {
4 | "AzureWebJobsStorage": "",
5 | "FUNCTIONS_WORKER_RUNTIME": "node"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/main/function.json:
--------------------------------------------------------------------------------
1 | {
2 | "bindings": [
3 | {
4 | "authLevel": "anonymous",
5 | "type": "httpTrigger",
6 | "direction": "in",
7 | "name": "req",
8 | "route": "{*segments}"
9 | },
10 | {
11 | "type": "http",
12 | "direction": "out",
13 | "name": "res"
14 | }
15 | ],
16 | "scriptFile": "../dist/main/index.js"
17 | }
18 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/main/index.ts:
--------------------------------------------------------------------------------
1 | import { Context, HttpRequest } from '@azure/functions';
2 | import { AzureHttpAdapter } from '@nestjs/azure-func-http';
3 | import { createApp } from '../src/main.azure';
4 |
5 | export default function(context: Context, req: HttpRequest): void {
6 | AzureHttpAdapter.handle(createApp, context, req);
7 | }
8 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/main/sample.dat:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Azure"
3 | }
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/nest-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/nest-cli",
3 | "collection": "@nestjs/schematics",
4 | "sourceRoot": "src",
5 | "compilerOptions": {
6 | "deleteOutDir": true
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/proxies.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/proxies",
3 | "proxies": {}
4 | }
5 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/src/app.controller.ts:
--------------------------------------------------------------------------------
1 | import { Controller } from '@nestjs/common';
2 |
3 | @Controller()
4 | export class AppController {}
5 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/src/app.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 |
3 | @Injectable()
4 | export class AppService {
5 | getHello(): string {
6 | return 'Hello World!';
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/src/auth/constants.ts:
--------------------------------------------------------------------------------
1 | export const jwtConstants = {
2 | secret:
3 | 'DO NOT USE THIS VALUE. INSTEAD, CREATE A COMPLEX SECRET AND KEEP IT SAFE OUTSIDE OF THE SOURCE CODE.',
4 | };
5 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/src/auth/public.decorator.ts:
--------------------------------------------------------------------------------
1 | import { SetMetadata } from '@nestjs/common';
2 |
3 | export const IS_PUBLIC_KEY = 'isPublic';
4 | export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
5 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/src/diary/interface/diary.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Diaries = Array;
4 | export interface Diary extends Item {
5 | date?: string;
6 | exercise?: string;
7 | sets?: number;
8 | reps?: number;
9 | }
10 |
11 | export interface DiariesAPI extends Collection {
12 | items: Diaries;
13 | }
14 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/src/exercises/dto/create-exercises.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiPropertyOptional } from '@nestjs/swagger';
2 | import { Exercise } from '../interface/exercises.interface';
3 |
4 | export class CreateExercisesDto implements Exercise {
5 | @ApiPropertyOptional()
6 | id: string;
7 |
8 | @ApiPropertyOptional()
9 | description: string;
10 | }
11 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/src/exercises/interface/exercises.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Exercises = Array;
4 | export interface Exercise extends Item {
5 | description?: string;
6 | }
7 |
8 | export interface ExercisesAPI extends Collection {
9 | items: Exercises;
10 | }
11 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/src/main.azure.ts:
--------------------------------------------------------------------------------
1 | import { INestApplication } from '@nestjs/common';
2 | import { NestFactory } from '@nestjs/core';
3 | import { AppModule } from './app.module';
4 |
5 | export async function createApp(): Promise {
6 | const app = await NestFactory.create(AppModule);
7 | app.setGlobalPrefix('api');
8 |
9 | await app.init();
10 | return app;
11 | }
12 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/src/users/db/users.data.ts:
--------------------------------------------------------------------------------
1 | import { Users } from '../interface/users.interface';
2 |
3 | export const users: Users = [
4 | {
5 | id: '1',
6 | username: 'mario',
7 | password: '1234',
8 | name: 'mario',
9 | },
10 | {
11 | id: '2',
12 | username: 'gabriel',
13 | password: '1234',
14 | name: 'gabriel',
15 | },
16 | ];
17 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/src/users/dto/get-users.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { UsersAPI } from '../interface/users.interface';
3 | import { CreateUsersDto } from './create-users.dto';
4 |
5 | export class GetUsersDTO implements UsersAPI {
6 | @ApiProperty()
7 | hasNext: boolean;
8 |
9 | @ApiProperty({ type: () => [CreateUsersDto] })
10 | items: Array;
11 | }
12 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/src/users/interface/users.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Users = Array;
4 | export interface User extends Item {
5 | username?: string;
6 | password?: string;
7 | name?: string;
8 | }
9 |
10 | export interface UsersAPI extends Collection {
11 | items: Users;
12 | }
13 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/src/utils/interfaces/collection.interface.ts:
--------------------------------------------------------------------------------
1 | export interface Collection {
2 | hasNext?: boolean;
3 | items: Items;
4 | }
5 |
6 | export interface Item {
7 | id?: string;
8 | }
9 |
10 | export type Items = Array
- ;
11 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/src/utils/interfaces/error.interface.ts:
--------------------------------------------------------------------------------
1 | export interface Error {
2 | code: 'string';
3 | message: 'string';
4 | detailedMessage: 'string';
5 | helpUrl: 'string';
6 | details: 'string';
7 | }
8 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/src/utils/interfaces/query.interface.ts:
--------------------------------------------------------------------------------
1 | export interface QueryApi {
2 | search?: string;
3 | filter?: string;
4 | page?: string;
5 | pageSize?: string;
6 | }
7 |
8 | export interface ParamQueryId {
9 | id?: string;
10 | }
11 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/test/jest-e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "moduleFileExtensions": ["js", "json", "ts"],
3 | "rootDir": ".",
4 | "testEnvironment": "node",
5 | "testRegex": ".e2e-spec.ts$",
6 | "transform": {
7 | "^.+\\.(t|j)s$": "ts-jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ch12/gym-diary-backend/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch12/gym-diary/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/ch12/gym-diary/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/ch12/gym-diary/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3 | "recommendations": ["angular.ng-template"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch12/gym-diary/cypress.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'cypress'
2 |
3 | export default defineConfig({
4 |
5 | e2e: {
6 | 'baseUrl': 'http://localhost:4200'
7 | },
8 |
9 |
10 | component: {
11 | devServer: {
12 | framework: 'angular',
13 | bundler: 'webpack',
14 | },
15 | specPattern: '**/*.cy.ts'
16 | }
17 |
18 | })
--------------------------------------------------------------------------------
/ch12/gym-diary/cypress/e2e/login.cy.ts:
--------------------------------------------------------------------------------
1 | describe('Login Page:', () => {
2 | it('should login to the diary with the correct credentials.', () => {
3 | cy.visit('/');
4 | cy.get('#username').type('mario');
5 | cy.get('#password').type('1234');
6 | cy.get('[data-cy="submit"]').click();
7 | cy.contains('Workout diary');
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/ch12/gym-diary/cypress/fixtures/example.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Using fixtures to represent data",
3 | "email": "hello@cypress.io"
4 | }
5 |
--------------------------------------------------------------------------------
/ch12/gym-diary/cypress/support/component-index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Components App
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/ch12/gym-diary/cypress/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "include": ["**/*.ts"],
4 | "compilerOptions": {
5 | "sourceMap": false,
6 | "types": ["cypress"]
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch12/gym-diary/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [require('prettier-plugin-tailwindcss')],
3 | tailwindConfig: './tailwind.config.js',
4 | }
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/app.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch12/gym-diary/src/app/app.component.css
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/diary/diary/diary.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch12/gym-diary/src/app/diary/diary/diary.component.css
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/diary/entry-item/entry-item.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch12/gym-diary/src/app/diary/entry-item/entry-item.component.css
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/diary/interfaces/exercise-set.ts:
--------------------------------------------------------------------------------
1 | export interface ExerciseSet {
2 | id?: string;
3 | date: Date;
4 | exercise: string;
5 | sets: number;
6 | reps: number;
7 | }
8 |
9 | export type ExerciseSetList = Array;
10 |
11 | export interface ExerciseSetListAPI {
12 | hasNext: boolean;
13 | items: ExerciseSetList;
14 | }
15 |
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/diary/interfaces/exercise.ts:
--------------------------------------------------------------------------------
1 | export interface Exercise {
2 | id?: string;
3 | description: string;
4 | }
5 |
6 | export type ExerciseList = Array;
7 |
8 | export interface ExerciseListAPI {
9 | hasNext: boolean;
10 | items: ExerciseList;
11 | }
12 |
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/diary/list-entries/list-entries.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch12/gym-diary/src/app/diary/list-entries/list-entries.component.css
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/diary/new-entry-form-reactive/new-entry-form-reactive.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch12/gym-diary/src/app/diary/new-entry-form-reactive/new-entry-form-reactive.component.css
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/diary/new-entry-form-template/new-entry-form-template.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch12/gym-diary/src/app/diary/new-entry-form-template/new-entry-form-template.component.css
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/diary/new-item-button/new-item-button.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch12/gym-diary/src/app/diary/new-item-button/new-item-button.component.css
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/diary/new-item-button/new-item-button.component.html:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/error-page/error-page.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch12/gym-diary/src/app/error-page/error-page.component.css
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/error-page/error-page.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-error-page',
5 | templateUrl: './error-page.component.html',
6 | styleUrls: ['./error-page.component.css']
7 | })
8 | export class ErrorPageComponent {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/exercise/exercise/exercise.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch12/gym-diary/src/app/exercise/exercise/exercise.component.css
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/exercise/exercise/exercise.component.cy.ts:
--------------------------------------------------------------------------------
1 | import { ExerciseComponent } from './exercise.component'
2 |
3 | describe('ExerciseComponent', () => {
4 | it('should mount', () => {
5 | cy.mount(ExerciseComponent)
6 | })
7 | })
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/exercise/exercise/exercise.component.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/exercise/exercise/exercise.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-exercise',
5 | templateUrl: './exercise.component.html',
6 | styleUrls: ['./exercise.component.css'],
7 | })
8 | export class ExerciseComponent {
9 | elementUrl = 'http://localhost:8080/main.js';
10 | }
11 |
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/home/home.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch12/gym-diary/src/app/home/home.component.css
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/home/home.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 |
4 | import { HomeRoutingModule } from './home-routing.module';
5 | import { HomeComponent } from './home.component';
6 |
7 | @NgModule({
8 | declarations: [HomeComponent],
9 | imports: [CommonModule, HomeRoutingModule],
10 | })
11 | export class HomeModule {}
12 |
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/loading-overlay/loading-overlay.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch12/gym-diary/src/app/loading-overlay/loading-overlay.component.css
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/loading-overlay/loading-overlay.component.html:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/loading-overlay/loading-overlay.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-loading-overlay',
5 | templateUrl: './loading-overlay.component.html',
6 | styleUrls: ['./loading-overlay.component.css']
7 | })
8 | export class LoadingOverlayComponent {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/login/auth.ts:
--------------------------------------------------------------------------------
1 | export interface LoginForm {
2 | username: string;
3 | password: string;
4 | }
5 |
6 | export interface Token {
7 | access_token: string;
8 | }
9 |
--------------------------------------------------------------------------------
/ch12/gym-diary/src/app/login/login.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch12/gym-diary/src/app/login/login.component.css
--------------------------------------------------------------------------------
/ch12/gym-diary/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch12/gym-diary/src/assets/.gitkeep
--------------------------------------------------------------------------------
/ch12/gym-diary/src/environments/environment.development.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: false,
3 | apiUrl: 'http://localhost:3000'
4 | };
5 |
--------------------------------------------------------------------------------
/ch12/gym-diary/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true,
3 | apiUrl: 'https://gymdiaryangularboook.azurewebsites.net/api',
4 | };
5 |
--------------------------------------------------------------------------------
/ch12/gym-diary/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch12/gym-diary/src/favicon.ico
--------------------------------------------------------------------------------
/ch12/gym-diary/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | GymDiary
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch12/gym-diary/src/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
2 |
3 | import { AppModule } from './app/app.module';
4 |
5 |
6 | platformBrowserDynamic().bootstrapModule(AppModule)
7 | .catch(err => console.error(err));
8 |
--------------------------------------------------------------------------------
/ch12/gym-diary/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 | @tailwind base;
3 | @tailwind components;
4 | @tailwind utilities;
--------------------------------------------------------------------------------
/ch12/gym-diary/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./src/**/*.{html,ts}",
5 | ],
6 | theme: {
7 | extend: {},
8 | },
9 | plugins: [],
10 | }
11 |
--------------------------------------------------------------------------------
/ch12/gym-diary/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts"
10 | ],
11 | "include": [
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch12/gym-diary/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "include": [
11 | "src/**/*.spec.ts",
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch12/gym_exercises/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/ch12/gym_exercises/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3 | "recommendations": ["angular.ng-template"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch12/gym_exercises/src/app/app.component.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
--------------------------------------------------------------------------------
/ch12/gym_exercises/src/app/app.config.ts:
--------------------------------------------------------------------------------
1 | import { ApplicationConfig } from '@angular/core';
2 | import { provideHttpClient } from '@angular/common/http';
3 |
4 | export const appConfig: ApplicationConfig = {
5 | providers: [provideHttpClient()],
6 | };
7 |
--------------------------------------------------------------------------------
/ch12/gym_exercises/src/app/exercise.ts:
--------------------------------------------------------------------------------
1 | export interface Exercise {
2 | id?: string;
3 | description: string;
4 | }
5 |
6 | export type ExerciseList = Array;
7 |
8 | export interface ExerciseListAPI {
9 | hasNext: boolean;
10 | items: ExerciseList;
11 | }
12 |
--------------------------------------------------------------------------------
/ch12/gym_exercises/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch12/gym_exercises/src/assets/.gitkeep
--------------------------------------------------------------------------------
/ch12/gym_exercises/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch12/gym_exercises/src/favicon.ico
--------------------------------------------------------------------------------
/ch12/gym_exercises/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | GymExercises
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch12/gym_exercises/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 | /*@tailwind base;
3 | @tailwind components;
4 | @tailwind utilities;*/
--------------------------------------------------------------------------------
/ch12/gym_exercises/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./src/**/*.{html,ts}",
5 | ],
6 | theme: {
7 | extend: {},
8 | },
9 | plugins: [],
10 | }
11 |
--------------------------------------------------------------------------------
/ch12/gym_exercises/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts"
10 | ],
11 | "include": [
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch12/gym_exercises/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "include": [
11 | "src/**/*.spec.ts",
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/.dockerignore:
--------------------------------------------------------------------------------
1 | Dockerfile
2 | .dockerignore
3 | node_modules
4 | npm-debug.log
5 | dist
6 | .env
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/.env.production:
--------------------------------------------------------------------------------
1 | NODE_ENV='production'
2 | PORT=80
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/.funcignore:
--------------------------------------------------------------------------------
1 | *.js.map
2 | *.ts
3 | .git*
4 | .vscode
5 | local.settings.json
6 | test
7 | tsconfig.json
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all"
4 | }
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "ms-azuretools.vscode-azurefunctions"
4 | ]
5 | }
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Attach to Node Functions",
6 | "type": "node",
7 | "request": "attach",
8 | "port": 9229,
9 | "preLaunchTask": "func: host start"
10 | }
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "azureFunctions.deploySubpath": ".",
3 | "azureFunctions.postDeployTask": "npm install (functions)",
4 | "azureFunctions.projectLanguage": "TypeScript",
5 | "azureFunctions.projectRuntime": "~4",
6 | "debug.internalConsoleOptions": "neverOpen",
7 | "azureFunctions.preDeployTask": "npm prune (functions)"
8 | }
9 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:latest
2 |
3 | WORKDIR /usr/src/api
4 |
5 | COPY . .
6 |
7 | COPY ./.env.production ./.env
8 |
9 | RUN npm install --quiet --no-optional --no-fund --loglevel=error
10 |
11 | RUN npm run build
12 |
13 | EXPOSE 80
14 |
15 | CMD [ "npm" ,"run", "start:prod" ]
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/host.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0"
3 | }
4 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/local.settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "IsEncrypted": false,
3 | "Values": {
4 | "AzureWebJobsStorage": "",
5 | "FUNCTIONS_WORKER_RUNTIME": "node"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/main/function.json:
--------------------------------------------------------------------------------
1 | {
2 | "bindings": [
3 | {
4 | "authLevel": "anonymous",
5 | "type": "httpTrigger",
6 | "direction": "in",
7 | "name": "req",
8 | "route": "{*segments}"
9 | },
10 | {
11 | "type": "http",
12 | "direction": "out",
13 | "name": "res"
14 | }
15 | ],
16 | "scriptFile": "../dist/main/index.js"
17 | }
18 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/main/index.ts:
--------------------------------------------------------------------------------
1 | import { Context, HttpRequest } from '@azure/functions';
2 | import { AzureHttpAdapter } from '@nestjs/azure-func-http';
3 | import { createApp } from '../src/main.azure';
4 |
5 | export default function(context: Context, req: HttpRequest): void {
6 | AzureHttpAdapter.handle(createApp, context, req);
7 | }
8 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/main/sample.dat:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Azure"
3 | }
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/nest-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/nest-cli",
3 | "collection": "@nestjs/schematics",
4 | "sourceRoot": "src",
5 | "compilerOptions": {
6 | "deleteOutDir": true
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/proxies.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/proxies",
3 | "proxies": {}
4 | }
5 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/src/app.controller.ts:
--------------------------------------------------------------------------------
1 | import { Controller } from '@nestjs/common';
2 |
3 | @Controller()
4 | export class AppController {}
5 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/src/app.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 |
3 | @Injectable()
4 | export class AppService {
5 | getHello(): string {
6 | return 'Hello World!';
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/src/auth/constants.ts:
--------------------------------------------------------------------------------
1 | export const jwtConstants = {
2 | secret:
3 | 'DO NOT USE THIS VALUE. INSTEAD, CREATE A COMPLEX SECRET AND KEEP IT SAFE OUTSIDE OF THE SOURCE CODE.',
4 | };
5 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/src/auth/public.decorator.ts:
--------------------------------------------------------------------------------
1 | import { SetMetadata } from '@nestjs/common';
2 |
3 | export const IS_PUBLIC_KEY = 'isPublic';
4 | export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
5 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/src/diary/interface/diary.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Diaries = Array;
4 | export interface Diary extends Item {
5 | date?: string;
6 | exercise?: string;
7 | sets?: number;
8 | reps?: number;
9 | }
10 |
11 | export interface DiariesAPI extends Collection {
12 | items: Diaries;
13 | }
14 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/src/exercises/dto/create-exercises.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiPropertyOptional } from '@nestjs/swagger';
2 | import { Exercise } from '../interface/exercises.interface';
3 |
4 | export class CreateExercisesDto implements Exercise {
5 | @ApiPropertyOptional()
6 | id: string;
7 |
8 | @ApiPropertyOptional()
9 | description: string;
10 | }
11 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/src/exercises/interface/exercises.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Exercises = Array;
4 | export interface Exercise extends Item {
5 | description?: string;
6 | }
7 |
8 | export interface ExercisesAPI extends Collection {
9 | items: Exercises;
10 | }
11 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/src/main.azure.ts:
--------------------------------------------------------------------------------
1 | import { INestApplication } from '@nestjs/common';
2 | import { NestFactory } from '@nestjs/core';
3 | import { AppModule } from './app.module';
4 |
5 | export async function createApp(): Promise {
6 | const app = await NestFactory.create(AppModule);
7 | app.setGlobalPrefix('api');
8 |
9 | await app.init();
10 | return app;
11 | }
12 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/src/users/db/users.data.ts:
--------------------------------------------------------------------------------
1 | import { Users } from '../interface/users.interface';
2 |
3 | export const users: Users = [
4 | {
5 | id: '1',
6 | username: 'mario',
7 | password: '1234',
8 | name: 'mario',
9 | },
10 | {
11 | id: '2',
12 | username: 'gabriel',
13 | password: '1234',
14 | name: 'gabriel',
15 | },
16 | ];
17 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/src/users/dto/get-users.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { UsersAPI } from '../interface/users.interface';
3 | import { CreateUsersDto } from './create-users.dto';
4 |
5 | export class GetUsersDTO implements UsersAPI {
6 | @ApiProperty()
7 | hasNext: boolean;
8 |
9 | @ApiProperty({ type: () => [CreateUsersDto] })
10 | items: Array;
11 | }
12 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/src/users/interface/users.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Users = Array;
4 | export interface User extends Item {
5 | username?: string;
6 | password?: string;
7 | name?: string;
8 | }
9 |
10 | export interface UsersAPI extends Collection {
11 | items: Users;
12 | }
13 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/src/utils/interfaces/collection.interface.ts:
--------------------------------------------------------------------------------
1 | export interface Collection {
2 | hasNext?: boolean;
3 | items: Items;
4 | }
5 |
6 | export interface Item {
7 | id?: string;
8 | }
9 |
10 | export type Items = Array
- ;
11 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/src/utils/interfaces/error.interface.ts:
--------------------------------------------------------------------------------
1 | export interface Error {
2 | code: 'string';
3 | message: 'string';
4 | detailedMessage: 'string';
5 | helpUrl: 'string';
6 | details: 'string';
7 | }
8 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/src/utils/interfaces/query.interface.ts:
--------------------------------------------------------------------------------
1 | export interface QueryApi {
2 | search?: string;
3 | filter?: string;
4 | page?: string;
5 | pageSize?: string;
6 | }
7 |
8 | export interface ParamQueryId {
9 | id?: string;
10 | }
11 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/test/jest-e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "moduleFileExtensions": ["js", "json", "ts"],
3 | "rootDir": ".",
4 | "testEnvironment": "node",
5 | "testRegex": ".e2e-spec.ts$",
6 | "transform": {
7 | "^.+\\.(t|j)s$": "ts-jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ch13/gym-diary-backend/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch13/gym-diary/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/ch13/gym-diary/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/ch13/gym-diary/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3 | "recommendations": ["angular.ng-template"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch13/gym-diary/cypress.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'cypress'
2 |
3 | export default defineConfig({
4 |
5 | e2e: {
6 | 'baseUrl': 'http://localhost:4200'
7 | },
8 |
9 |
10 | component: {
11 | devServer: {
12 | framework: 'angular',
13 | bundler: 'webpack',
14 | },
15 | specPattern: '**/*.cy.ts'
16 | }
17 |
18 | })
--------------------------------------------------------------------------------
/ch13/gym-diary/cypress/e2e/login.cy.ts:
--------------------------------------------------------------------------------
1 | describe('Login Page:', () => {
2 | it('should login to the diary with the correct credentials.', () => {
3 | cy.visit('/');
4 | cy.get('#username').type('mario');
5 | cy.get('#password').type('1234');
6 | cy.get('[data-cy="submit"]').click();
7 | cy.contains('Workout diary');
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/ch13/gym-diary/cypress/fixtures/example.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Using fixtures to represent data",
3 | "email": "hello@cypress.io"
4 | }
5 |
--------------------------------------------------------------------------------
/ch13/gym-diary/cypress/support/component-index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Components App
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/ch13/gym-diary/cypress/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "include": ["**/*.ts"],
4 | "compilerOptions": {
5 | "sourceMap": false,
6 | "types": ["cypress"]
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch13/gym-diary/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [require('prettier-plugin-tailwindcss')],
3 | tailwindConfig: './tailwind.config.js',
4 | }
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/app.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch13/gym-diary/src/app/app.component.css
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/app.component.html:
--------------------------------------------------------------------------------
1 | @if (loadService.isLoading()) {
2 |
3 | }
4 |
5 |
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/diary/diary/diary.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch13/gym-diary/src/app/diary/diary/diary.component.css
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/diary/entry-item/entry-item.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch13/gym-diary/src/app/diary/entry-item/entry-item.component.css
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/diary/interfaces/exercise-set.ts:
--------------------------------------------------------------------------------
1 | export interface ExerciseSet {
2 | id?: string;
3 | date: Date;
4 | exercise: string;
5 | sets: number;
6 | reps: number;
7 | }
8 |
9 | export type ExerciseSetList = Array;
10 |
11 | export interface ExerciseSetListAPI {
12 | hasNext: boolean;
13 | items: ExerciseSetList;
14 | }
15 |
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/diary/interfaces/exercise.ts:
--------------------------------------------------------------------------------
1 | export interface Exercise {
2 | id?: string;
3 | description: string;
4 | }
5 |
6 | export type ExerciseList = Array;
7 |
8 | export interface ExerciseListAPI {
9 | hasNext: boolean;
10 | items: ExerciseList;
11 | }
12 |
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/diary/list-entries/list-entries.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch13/gym-diary/src/app/diary/list-entries/list-entries.component.css
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/diary/new-entry-form-reactive/new-entry-form-reactive.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch13/gym-diary/src/app/diary/new-entry-form-reactive/new-entry-form-reactive.component.css
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/diary/new-entry-form-template/new-entry-form-template.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch13/gym-diary/src/app/diary/new-entry-form-template/new-entry-form-template.component.css
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/diary/new-item-button/new-item-button.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch13/gym-diary/src/app/diary/new-item-button/new-item-button.component.css
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/diary/new-item-button/new-item-button.component.html:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/error-page/error-page.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch13/gym-diary/src/app/error-page/error-page.component.css
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/error-page/error-page.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-error-page',
5 | templateUrl: './error-page.component.html',
6 | styleUrls: ['./error-page.component.css']
7 | })
8 | export class ErrorPageComponent {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/exercise/exercise/exercise.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch13/gym-diary/src/app/exercise/exercise/exercise.component.css
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/exercise/exercise/exercise.component.cy.ts:
--------------------------------------------------------------------------------
1 | import { ExerciseComponent } from './exercise.component'
2 |
3 | describe('ExerciseComponent', () => {
4 | it('should mount', () => {
5 | cy.mount(ExerciseComponent)
6 | })
7 | })
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/exercise/exercise/exercise.component.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/exercise/exercise/exercise.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-exercise',
5 | templateUrl: './exercise.component.html',
6 | styleUrls: ['./exercise.component.css'],
7 | })
8 | export class ExerciseComponent {
9 | elementUrl = 'http://localhost:8080/main.js';
10 | }
11 |
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/home/home.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch13/gym-diary/src/app/home/home.component.css
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/home/home.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 |
4 | import { HomeRoutingModule } from './home-routing.module';
5 | import { HomeComponent } from './home.component';
6 |
7 | @NgModule({
8 | declarations: [HomeComponent],
9 | imports: [CommonModule, HomeRoutingModule],
10 | })
11 | export class HomeModule {}
12 |
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/loading-overlay/load.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, signal } from '@angular/core';
2 |
3 | @Injectable({
4 | providedIn: 'root',
5 | })
6 | export class LoadService {
7 | isLoading = signal(false);
8 |
9 | showLoader() {
10 | this.isLoading.set(true);
11 | }
12 |
13 | hideLoader() {
14 | this.isLoading.set(false);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/loading-overlay/loading-overlay.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch13/gym-diary/src/app/loading-overlay/loading-overlay.component.css
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/loading-overlay/loading-overlay.component.html:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/loading-overlay/loading-overlay.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-loading-overlay',
5 | templateUrl: './loading-overlay.component.html',
6 | styleUrls: ['./loading-overlay.component.css']
7 | })
8 | export class LoadingOverlayComponent {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/login/auth.ts:
--------------------------------------------------------------------------------
1 | export interface LoginForm {
2 | username: string;
3 | password: string;
4 | }
5 |
6 | export interface Token {
7 | access_token: string;
8 | }
9 |
--------------------------------------------------------------------------------
/ch13/gym-diary/src/app/login/login.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch13/gym-diary/src/app/login/login.component.css
--------------------------------------------------------------------------------
/ch13/gym-diary/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch13/gym-diary/src/assets/.gitkeep
--------------------------------------------------------------------------------
/ch13/gym-diary/src/environments/environment.development.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: false,
3 | apiUrl: 'http://localhost:3000'
4 | };
5 |
--------------------------------------------------------------------------------
/ch13/gym-diary/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true,
3 | apiUrl: 'https://gymdiaryangularboook.azurewebsites.net/api',
4 | };
5 |
--------------------------------------------------------------------------------
/ch13/gym-diary/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch13/gym-diary/src/favicon.ico
--------------------------------------------------------------------------------
/ch13/gym-diary/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | GymDiary
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch13/gym-diary/src/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
2 |
3 | import { AppModule } from './app/app.module';
4 |
5 |
6 | platformBrowserDynamic().bootstrapModule(AppModule)
7 | .catch(err => console.error(err));
8 |
--------------------------------------------------------------------------------
/ch13/gym-diary/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./src/**/*.{html,ts}",
5 | ],
6 | theme: {
7 | extend: {},
8 | },
9 | plugins: [],
10 | }
11 |
--------------------------------------------------------------------------------
/ch13/gym-diary/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts"
10 | ],
11 | "include": [
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch13/gym-diary/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "include": [
11 | "src/**/*.spec.ts",
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch13/gym_exercises/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/ch13/gym_exercises/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3 | "recommendations": ["angular.ng-template"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch13/gym_exercises/src/app/app.component.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
--------------------------------------------------------------------------------
/ch13/gym_exercises/src/app/app.config.ts:
--------------------------------------------------------------------------------
1 | import { ApplicationConfig } from '@angular/core';
2 | import { provideHttpClient } from '@angular/common/http';
3 |
4 | export const appConfig: ApplicationConfig = {
5 | providers: [provideHttpClient()],
6 | };
7 |
--------------------------------------------------------------------------------
/ch13/gym_exercises/src/app/exercise.ts:
--------------------------------------------------------------------------------
1 | export interface Exercise {
2 | id?: string;
3 | description: string;
4 | }
5 |
6 | export type ExerciseList = Array;
7 |
8 | export interface ExerciseListAPI {
9 | hasNext: boolean;
10 | items: ExerciseList;
11 | }
12 |
--------------------------------------------------------------------------------
/ch13/gym_exercises/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch13/gym_exercises/src/assets/.gitkeep
--------------------------------------------------------------------------------
/ch13/gym_exercises/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch13/gym_exercises/src/favicon.ico
--------------------------------------------------------------------------------
/ch13/gym_exercises/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | GymExercises
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch13/gym_exercises/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 | /*@tailwind base;
3 | @tailwind components;
4 | @tailwind utilities;*/
--------------------------------------------------------------------------------
/ch13/gym_exercises/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./src/**/*.{html,ts}",
5 | ],
6 | theme: {
7 | extend: {},
8 | },
9 | plugins: [],
10 | }
11 |
--------------------------------------------------------------------------------
/ch13/gym_exercises/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts"
10 | ],
11 | "include": [
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch13/gym_exercises/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "include": [
11 | "src/**/*.spec.ts",
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch2/jsmodule_example/index.mjs:
--------------------------------------------------------------------------------
1 | import {sum} from './sum.mjs'
2 |
3 | const numberA = 5;
4 | const numberB = 10;
5 |
6 | console.log(sum(numberA,numberB));
--------------------------------------------------------------------------------
/ch2/jsmodule_example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jsmodule_example",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC"
11 | }
12 |
--------------------------------------------------------------------------------
/ch2/jsmodule_example/sum.mjs:
--------------------------------------------------------------------------------
1 |
2 | export function sum(numberA,numberB){
3 | return numberA + numberB;
4 | }
--------------------------------------------------------------------------------
/ch2/talktalk/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/ch2/talktalk/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3 | "recommendations": ["angular.ng-template"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch2/talktalk/src/app/app.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch2/talktalk/src/app/app.component.css
--------------------------------------------------------------------------------
/ch2/talktalk/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ch2/talktalk/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-root',
5 | templateUrl: './app.component.html',
6 | styleUrls: ['./app.component.css']
7 | })
8 | export class AppComponent {
9 | title = 'talktalk';
10 | }
11 |
--------------------------------------------------------------------------------
/ch2/talktalk/src/app/home/home/home.component.css:
--------------------------------------------------------------------------------
1 | .sidenav-container {
2 | height: 100%;
3 | }
4 |
5 | .sidenav {
6 | width: 200px;
7 | }
8 |
9 | .sidenav .mat-toolbar {
10 | background: inherit;
11 | }
12 |
13 | .mat-toolbar.mat-primary {
14 | position: sticky;
15 | top: 0;
16 | z-index: 1;
17 | }
18 |
--------------------------------------------------------------------------------
/ch2/talktalk/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch2/talktalk/src/assets/.gitkeep
--------------------------------------------------------------------------------
/ch2/talktalk/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch2/talktalk/src/favicon.ico
--------------------------------------------------------------------------------
/ch2/talktalk/src/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
2 |
3 | import { AppModule } from './app/app.module';
4 |
5 |
6 | platformBrowserDynamic().bootstrapModule(AppModule)
7 | .catch(err => console.error(err));
8 |
--------------------------------------------------------------------------------
/ch2/talktalk/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 |
3 | html, body { height: 100%; }
4 | body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
5 |
--------------------------------------------------------------------------------
/ch2/talktalk/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts"
10 | ],
11 | "include": [
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch2/talktalk/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "include": [
11 | "src/**/*.spec.ts",
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch3/typescript-example/build/basic_types/animals.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 |
--------------------------------------------------------------------------------
/ch3/typescript-example/build/basic_types/any.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | exports.any_example = void 0;
4 | function any_example() {
5 | let information;
6 | information = 'Mario';
7 | console.log(`Name: ${information}`);
8 | information = 7;
9 | console.log(`Age: ${information}`);
10 | }
11 | exports.any_example = any_example;
12 |
--------------------------------------------------------------------------------
/ch3/typescript-example/nodemon.json:
--------------------------------------------------------------------------------
1 | {
2 | "watch": ["src"],
3 | "ext": ".ts,.js",
4 | "ignore": [],
5 | "exec": "npx ts-node ./src/index.ts"
6 | }
--------------------------------------------------------------------------------
/ch3/typescript-example/src/basic_types/array.ts:
--------------------------------------------------------------------------------
1 | export function array_example() {
2 | let names: Array;
3 | let surnames: string[];
4 |
5 | names = ["Mario", "Gabriel", "Lucy"];
6 | surnames = ["Camillo", "Smith"];
7 |
8 | names.forEach((name) => console.log(`Name:${name}`));
9 | surnames.forEach((surname) => console.log(`Surname:${surname}`));
10 | }
11 |
--------------------------------------------------------------------------------
/ch3/typescript-example/src/basic_types/primitive.ts:
--------------------------------------------------------------------------------
1 | export function primitive_example() {
2 | let name = "Mario";
3 | let age = 9;
4 | let isAlive = true;
5 |
6 | console.log(`Name:${name} Age:${age} is alive:${isAlive ? "yes" : "no"}`);
7 | }
8 |
--------------------------------------------------------------------------------
/ch4/gym-diary/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/ch4/gym-diary/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3 | "recommendations": ["angular.ng-template"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch4/gym-diary/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [require('prettier-plugin-tailwindcss')],
3 | tailwindConfig: './tailwind.config.js',
4 | }
--------------------------------------------------------------------------------
/ch4/gym-diary/src/app/app.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch4/gym-diary/src/app/app.component.css
--------------------------------------------------------------------------------
/ch4/gym-diary/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/ch4/gym-diary/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-root',
5 | templateUrl: './app.component.html',
6 | styleUrls: ['./app.component.css']
7 | })
8 | export class AppComponent {
9 | title = 'gym-diary';
10 | }
11 |
--------------------------------------------------------------------------------
/ch4/gym-diary/src/app/diary/diary/diary.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch4/gym-diary/src/app/diary/diary/diary.component.css
--------------------------------------------------------------------------------
/ch4/gym-diary/src/app/diary/entry-item/entry-item.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch4/gym-diary/src/app/diary/entry-item/entry-item.component.css
--------------------------------------------------------------------------------
/ch4/gym-diary/src/app/diary/interfaces/exercise-set.ts:
--------------------------------------------------------------------------------
1 | export interface ExerciseSet {
2 | id?: string;
3 | date: Date;
4 | exercise: string;
5 | sets: number;
6 | reps: number;
7 | }
8 |
9 | export type ExerciseSetList = Array;
10 |
--------------------------------------------------------------------------------
/ch4/gym-diary/src/app/diary/list-entries/list-entries.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch4/gym-diary/src/app/diary/list-entries/list-entries.component.css
--------------------------------------------------------------------------------
/ch4/gym-diary/src/app/diary/new-item-button/new-item-button.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch4/gym-diary/src/app/diary/new-item-button/new-item-button.component.css
--------------------------------------------------------------------------------
/ch4/gym-diary/src/app/diary/new-item-button/new-item-button.component.html:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/ch4/gym-diary/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch4/gym-diary/src/assets/.gitkeep
--------------------------------------------------------------------------------
/ch4/gym-diary/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch4/gym-diary/src/favicon.ico
--------------------------------------------------------------------------------
/ch4/gym-diary/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | GymDiary
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch4/gym-diary/src/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
2 |
3 | import { AppModule } from './app/app.module';
4 |
5 |
6 | platformBrowserDynamic().bootstrapModule(AppModule)
7 | .catch(err => console.error(err));
8 |
--------------------------------------------------------------------------------
/ch4/gym-diary/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 | @tailwind base;
3 | @tailwind components;
4 | @tailwind utilities;
--------------------------------------------------------------------------------
/ch4/gym-diary/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./src/**/*.{html,ts}",
5 | ],
6 | theme: {
7 | extend: {},
8 | },
9 | plugins: [],
10 | }
11 |
--------------------------------------------------------------------------------
/ch4/gym-diary/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts"
10 | ],
11 | "include": [
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch4/gym-diary/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "include": [
11 | "src/**/*.spec.ts",
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch5/gym-diary-backend/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all"
4 | }
--------------------------------------------------------------------------------
/ch5/gym-diary-backend/nest-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/nest-cli",
3 | "collection": "@nestjs/schematics",
4 | "sourceRoot": "src",
5 | "compilerOptions": {
6 | "deleteOutDir": true
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch5/gym-diary-backend/src/app.controller.ts:
--------------------------------------------------------------------------------
1 | import { Controller } from '@nestjs/common';
2 |
3 | @Controller()
4 | export class AppController {}
5 |
--------------------------------------------------------------------------------
/ch5/gym-diary-backend/src/app.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 |
3 | @Injectable()
4 | export class AppService {
5 | getHello(): string {
6 | return 'Hello World!';
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch5/gym-diary-backend/src/auth/constants.ts:
--------------------------------------------------------------------------------
1 | export const jwtConstants = {
2 | secret:
3 | 'DO NOT USE THIS VALUE. INSTEAD, CREATE A COMPLEX SECRET AND KEEP IT SAFE OUTSIDE OF THE SOURCE CODE.',
4 | };
5 |
--------------------------------------------------------------------------------
/ch5/gym-diary-backend/src/auth/public.decorator.ts:
--------------------------------------------------------------------------------
1 | import { SetMetadata } from '@nestjs/common';
2 |
3 | export const IS_PUBLIC_KEY = 'isPublic';
4 | export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
5 |
--------------------------------------------------------------------------------
/ch5/gym-diary-backend/src/diary/interface/diary.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Diaries = Array;
4 | export interface Diary extends Item {
5 | date?: Date;
6 | exercise?: string;
7 | sets?: number;
8 | reps?: number;
9 | }
10 |
11 | export interface DiariesAPI extends Collection {
12 | items: Diaries;
13 | }
14 |
--------------------------------------------------------------------------------
/ch5/gym-diary-backend/src/exercises/dto/create-exercises.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiPropertyOptional } from '@nestjs/swagger';
2 | import { Exercise } from '../interface/exercises.interface';
3 |
4 | export class CreateExercisesDto implements Exercise {
5 | @ApiPropertyOptional()
6 | id: string;
7 |
8 | @ApiPropertyOptional()
9 | description: string;
10 | }
11 |
--------------------------------------------------------------------------------
/ch5/gym-diary-backend/src/exercises/interface/exercises.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Exercises = Array;
4 | export interface Exercise extends Item {
5 | description?: string;
6 | }
7 |
8 | export interface ExercisesAPI extends Collection {
9 | items: Exercises;
10 | }
11 |
--------------------------------------------------------------------------------
/ch5/gym-diary-backend/src/users/db/users.data.ts:
--------------------------------------------------------------------------------
1 | import { Users } from '../interface/users.interface';
2 |
3 | export const users: Users = [
4 | {
5 | id: '1',
6 | username: 'mario@mario.com',
7 | password: '1234',
8 | name: 'mario',
9 | },
10 | {
11 | id: '2',
12 | username: 'gabriel@gabriel.com',
13 | password: '1234',
14 | name: 'gabriel',
15 | },
16 | ];
17 |
--------------------------------------------------------------------------------
/ch5/gym-diary-backend/src/users/dto/get-users.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { UsersAPI } from '../interface/users.interface';
3 | import { CreateUsersDto } from './create-users.dto';
4 |
5 | export class GetUsersDTO implements UsersAPI {
6 | @ApiProperty()
7 | hasNext: boolean;
8 |
9 | @ApiProperty({ type: () => [CreateUsersDto] })
10 | items: Array;
11 | }
12 |
--------------------------------------------------------------------------------
/ch5/gym-diary-backend/src/users/interface/users.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Users = Array;
4 | export interface User extends Item {
5 | username?: string;
6 | password?: string;
7 | name?: string;
8 | }
9 |
10 | export interface UsersAPI extends Collection {
11 | items: Users;
12 | }
13 |
--------------------------------------------------------------------------------
/ch5/gym-diary-backend/src/utils/interfaces/collection.interface.ts:
--------------------------------------------------------------------------------
1 | export interface Collection {
2 | hasNext?: boolean;
3 | items: Items;
4 | }
5 |
6 | export interface Item {
7 | id?: string;
8 | }
9 |
10 | export type Items = Array
- ;
11 |
--------------------------------------------------------------------------------
/ch5/gym-diary-backend/src/utils/interfaces/error.interface.ts:
--------------------------------------------------------------------------------
1 | export interface Error {
2 | code: 'string';
3 | message: 'string';
4 | detailedMessage: 'string';
5 | helpUrl: 'string';
6 | details: 'string';
7 | }
8 |
--------------------------------------------------------------------------------
/ch5/gym-diary-backend/src/utils/interfaces/query.interface.ts:
--------------------------------------------------------------------------------
1 | export interface QueryApi {
2 | search?: string;
3 | filter?: string;
4 | page?: string;
5 | pageSize?: string;
6 | }
7 |
8 | export interface ParamQueryId {
9 | id?: string;
10 | }
11 |
--------------------------------------------------------------------------------
/ch5/gym-diary-backend/test/jest-e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "moduleFileExtensions": ["js", "json", "ts"],
3 | "rootDir": ".",
4 | "testEnvironment": "node",
5 | "testRegex": ".e2e-spec.ts$",
6 | "transform": {
7 | "^.+\\.(t|j)s$": "ts-jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ch5/gym-diary-backend/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch5/gym-diary/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/ch5/gym-diary/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3 | "recommendations": ["angular.ng-template"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch5/gym-diary/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [require('prettier-plugin-tailwindcss')],
3 | tailwindConfig: './tailwind.config.js',
4 | }
--------------------------------------------------------------------------------
/ch5/gym-diary/src/app/app.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch5/gym-diary/src/app/app.component.css
--------------------------------------------------------------------------------
/ch5/gym-diary/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/ch5/gym-diary/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-root',
5 | templateUrl: './app.component.html',
6 | styleUrls: ['./app.component.css']
7 | })
8 | export class AppComponent {
9 | title = 'gym-diary';
10 | }
11 |
--------------------------------------------------------------------------------
/ch5/gym-diary/src/app/diary/diary/diary.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch5/gym-diary/src/app/diary/diary/diary.component.css
--------------------------------------------------------------------------------
/ch5/gym-diary/src/app/diary/entry-item/entry-item.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch5/gym-diary/src/app/diary/entry-item/entry-item.component.css
--------------------------------------------------------------------------------
/ch5/gym-diary/src/app/diary/interfaces/exercise-set.ts:
--------------------------------------------------------------------------------
1 | export interface ExerciseSet {
2 | id?: string;
3 | date: Date;
4 | exercise: string;
5 | sets: number;
6 | reps: number;
7 | }
8 |
9 | export type ExerciseSetList = Array;
10 |
11 | export interface ExerciseSetListAPI {
12 | hasNext: boolean;
13 | items: ExerciseSetList;
14 | }
15 |
--------------------------------------------------------------------------------
/ch5/gym-diary/src/app/diary/list-entries/list-entries.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch5/gym-diary/src/app/diary/list-entries/list-entries.component.css
--------------------------------------------------------------------------------
/ch5/gym-diary/src/app/diary/new-item-button/new-item-button.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch5/gym-diary/src/app/diary/new-item-button/new-item-button.component.css
--------------------------------------------------------------------------------
/ch5/gym-diary/src/app/diary/new-item-button/new-item-button.component.html:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/ch5/gym-diary/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch5/gym-diary/src/assets/.gitkeep
--------------------------------------------------------------------------------
/ch5/gym-diary/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch5/gym-diary/src/favicon.ico
--------------------------------------------------------------------------------
/ch5/gym-diary/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | GymDiary
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch5/gym-diary/src/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
2 |
3 | import { AppModule } from './app/app.module';
4 |
5 |
6 | platformBrowserDynamic().bootstrapModule(AppModule)
7 | .catch(err => console.error(err));
8 |
--------------------------------------------------------------------------------
/ch5/gym-diary/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 | @tailwind base;
3 | @tailwind components;
4 | @tailwind utilities;
--------------------------------------------------------------------------------
/ch5/gym-diary/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./src/**/*.{html,ts}",
5 | ],
6 | theme: {
7 | extend: {},
8 | },
9 | plugins: [],
10 | }
11 |
--------------------------------------------------------------------------------
/ch5/gym-diary/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts"
10 | ],
11 | "include": [
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch5/gym-diary/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "include": [
11 | "src/**/*.spec.ts",
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch6/gym-diary-backend/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all"
4 | }
--------------------------------------------------------------------------------
/ch6/gym-diary-backend/nest-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/nest-cli",
3 | "collection": "@nestjs/schematics",
4 | "sourceRoot": "src",
5 | "compilerOptions": {
6 | "deleteOutDir": true
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch6/gym-diary-backend/src/app.controller.ts:
--------------------------------------------------------------------------------
1 | import { Controller } from '@nestjs/common';
2 |
3 | @Controller()
4 | export class AppController {}
5 |
--------------------------------------------------------------------------------
/ch6/gym-diary-backend/src/app.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 |
3 | @Injectable()
4 | export class AppService {
5 | getHello(): string {
6 | return 'Hello World!';
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch6/gym-diary-backend/src/auth/constants.ts:
--------------------------------------------------------------------------------
1 | export const jwtConstants = {
2 | secret:
3 | 'DO NOT USE THIS VALUE. INSTEAD, CREATE A COMPLEX SECRET AND KEEP IT SAFE OUTSIDE OF THE SOURCE CODE.',
4 | };
5 |
--------------------------------------------------------------------------------
/ch6/gym-diary-backend/src/auth/public.decorator.ts:
--------------------------------------------------------------------------------
1 | import { SetMetadata } from '@nestjs/common';
2 |
3 | export const IS_PUBLIC_KEY = 'isPublic';
4 | export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
5 |
--------------------------------------------------------------------------------
/ch6/gym-diary-backend/src/diary/interface/diary.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Diaries = Array;
4 | export interface Diary extends Item {
5 | date?: Date;
6 | exercise?: string;
7 | sets?: number;
8 | reps?: number;
9 | }
10 |
11 | export interface DiariesAPI extends Collection {
12 | items: Diaries;
13 | }
14 |
--------------------------------------------------------------------------------
/ch6/gym-diary-backend/src/exercises/dto/create-exercises.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiPropertyOptional } from '@nestjs/swagger';
2 | import { Exercise } from '../interface/exercises.interface';
3 |
4 | export class CreateExercisesDto implements Exercise {
5 | @ApiPropertyOptional()
6 | id: string;
7 |
8 | @ApiPropertyOptional()
9 | description: string;
10 | }
11 |
--------------------------------------------------------------------------------
/ch6/gym-diary-backend/src/exercises/interface/exercises.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Exercises = Array;
4 | export interface Exercise extends Item {
5 | description?: string;
6 | }
7 |
8 | export interface ExercisesAPI extends Collection {
9 | items: Exercises;
10 | }
11 |
--------------------------------------------------------------------------------
/ch6/gym-diary-backend/src/users/db/users.data.ts:
--------------------------------------------------------------------------------
1 | import { Users } from '../interface/users.interface';
2 |
3 | export const users: Users = [
4 | {
5 | id: '1',
6 | username: 'mario@mario.com',
7 | password: '1234',
8 | name: 'mario',
9 | },
10 | {
11 | id: '2',
12 | username: 'gabriel@gabriel.com',
13 | password: '1234',
14 | name: 'gabriel',
15 | },
16 | ];
17 |
--------------------------------------------------------------------------------
/ch6/gym-diary-backend/src/users/dto/get-users.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { UsersAPI } from '../interface/users.interface';
3 | import { CreateUsersDto } from './create-users.dto';
4 |
5 | export class GetUsersDTO implements UsersAPI {
6 | @ApiProperty()
7 | hasNext: boolean;
8 |
9 | @ApiProperty({ type: () => [CreateUsersDto] })
10 | items: Array;
11 | }
12 |
--------------------------------------------------------------------------------
/ch6/gym-diary-backend/src/users/interface/users.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Users = Array;
4 | export interface User extends Item {
5 | username?: string;
6 | password?: string;
7 | name?: string;
8 | }
9 |
10 | export interface UsersAPI extends Collection {
11 | items: Users;
12 | }
13 |
--------------------------------------------------------------------------------
/ch6/gym-diary-backend/src/utils/interfaces/collection.interface.ts:
--------------------------------------------------------------------------------
1 | export interface Collection {
2 | hasNext?: boolean;
3 | items: Items;
4 | }
5 |
6 | export interface Item {
7 | id?: string;
8 | }
9 |
10 | export type Items = Array
- ;
11 |
--------------------------------------------------------------------------------
/ch6/gym-diary-backend/src/utils/interfaces/error.interface.ts:
--------------------------------------------------------------------------------
1 | export interface Error {
2 | code: 'string';
3 | message: 'string';
4 | detailedMessage: 'string';
5 | helpUrl: 'string';
6 | details: 'string';
7 | }
8 |
--------------------------------------------------------------------------------
/ch6/gym-diary-backend/src/utils/interfaces/query.interface.ts:
--------------------------------------------------------------------------------
1 | export interface QueryApi {
2 | search?: string;
3 | filter?: string;
4 | page?: string;
5 | pageSize?: string;
6 | }
7 |
8 | export interface ParamQueryId {
9 | id?: string;
10 | }
11 |
--------------------------------------------------------------------------------
/ch6/gym-diary-backend/test/jest-e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "moduleFileExtensions": ["js", "json", "ts"],
3 | "rootDir": ".",
4 | "testEnvironment": "node",
5 | "testRegex": ".e2e-spec.ts$",
6 | "transform": {
7 | "^.+\\.(t|j)s$": "ts-jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ch6/gym-diary-backend/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch6/gym-diary/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/ch6/gym-diary/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3 | "recommendations": ["angular.ng-template"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch6/gym-diary/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [require('prettier-plugin-tailwindcss')],
3 | tailwindConfig: './tailwind.config.js',
4 | }
--------------------------------------------------------------------------------
/ch6/gym-diary/src/app/app.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch6/gym-diary/src/app/app.component.css
--------------------------------------------------------------------------------
/ch6/gym-diary/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/ch6/gym-diary/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-root',
5 | templateUrl: './app.component.html',
6 | styleUrls: ['./app.component.css']
7 | })
8 | export class AppComponent {
9 | title = 'gym-diary';
10 | }
11 |
--------------------------------------------------------------------------------
/ch6/gym-diary/src/app/diary/diary/diary.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch6/gym-diary/src/app/diary/diary/diary.component.css
--------------------------------------------------------------------------------
/ch6/gym-diary/src/app/diary/entry-item/entry-item.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch6/gym-diary/src/app/diary/entry-item/entry-item.component.css
--------------------------------------------------------------------------------
/ch6/gym-diary/src/app/diary/interfaces/exercise-set.ts:
--------------------------------------------------------------------------------
1 | export interface ExerciseSet {
2 | id?: string;
3 | date: Date;
4 | exercise: string;
5 | sets: number;
6 | reps: number;
7 | }
8 |
9 | export type ExerciseSetList = Array;
10 |
11 | export interface ExerciseSetListAPI {
12 | hasNext: boolean;
13 | items: ExerciseSetList;
14 | }
15 |
--------------------------------------------------------------------------------
/ch6/gym-diary/src/app/diary/list-entries/list-entries.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch6/gym-diary/src/app/diary/list-entries/list-entries.component.css
--------------------------------------------------------------------------------
/ch6/gym-diary/src/app/diary/new-entry-form-reactive/new-entry-form-reactive.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch6/gym-diary/src/app/diary/new-entry-form-reactive/new-entry-form-reactive.component.css
--------------------------------------------------------------------------------
/ch6/gym-diary/src/app/diary/new-entry-form-template/new-entry-form-template.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch6/gym-diary/src/app/diary/new-entry-form-template/new-entry-form-template.component.css
--------------------------------------------------------------------------------
/ch6/gym-diary/src/app/diary/new-item-button/new-item-button.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch6/gym-diary/src/app/diary/new-item-button/new-item-button.component.css
--------------------------------------------------------------------------------
/ch6/gym-diary/src/app/diary/new-item-button/new-item-button.component.html:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/ch6/gym-diary/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch6/gym-diary/src/assets/.gitkeep
--------------------------------------------------------------------------------
/ch6/gym-diary/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch6/gym-diary/src/favicon.ico
--------------------------------------------------------------------------------
/ch6/gym-diary/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | GymDiary
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch6/gym-diary/src/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
2 |
3 | import { AppModule } from './app/app.module';
4 |
5 |
6 | platformBrowserDynamic().bootstrapModule(AppModule)
7 | .catch(err => console.error(err));
8 |
--------------------------------------------------------------------------------
/ch6/gym-diary/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 | @tailwind base;
3 | @tailwind components;
4 | @tailwind utilities;
--------------------------------------------------------------------------------
/ch6/gym-diary/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./src/**/*.{html,ts}",
5 | ],
6 | theme: {
7 | extend: {},
8 | },
9 | plugins: [],
10 | }
11 |
--------------------------------------------------------------------------------
/ch6/gym-diary/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts"
10 | ],
11 | "include": [
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch6/gym-diary/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "include": [
11 | "src/**/*.spec.ts",
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch7/gym-diary-backend/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all"
4 | }
--------------------------------------------------------------------------------
/ch7/gym-diary-backend/nest-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/nest-cli",
3 | "collection": "@nestjs/schematics",
4 | "sourceRoot": "src",
5 | "compilerOptions": {
6 | "deleteOutDir": true
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch7/gym-diary-backend/src/app.controller.ts:
--------------------------------------------------------------------------------
1 | import { Controller } from '@nestjs/common';
2 |
3 | @Controller()
4 | export class AppController {}
5 |
--------------------------------------------------------------------------------
/ch7/gym-diary-backend/src/app.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 |
3 | @Injectable()
4 | export class AppService {
5 | getHello(): string {
6 | return 'Hello World!';
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch7/gym-diary-backend/src/auth/constants.ts:
--------------------------------------------------------------------------------
1 | export const jwtConstants = {
2 | secret:
3 | 'DO NOT USE THIS VALUE. INSTEAD, CREATE A COMPLEX SECRET AND KEEP IT SAFE OUTSIDE OF THE SOURCE CODE.',
4 | };
5 |
--------------------------------------------------------------------------------
/ch7/gym-diary-backend/src/auth/public.decorator.ts:
--------------------------------------------------------------------------------
1 | import { SetMetadata } from '@nestjs/common';
2 |
3 | export const IS_PUBLIC_KEY = 'isPublic';
4 | export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
5 |
--------------------------------------------------------------------------------
/ch7/gym-diary-backend/src/diary/interface/diary.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Diaries = Array;
4 | export interface Diary extends Item {
5 | date?: string;
6 | exercise?: string;
7 | sets?: number;
8 | reps?: number;
9 | }
10 |
11 | export interface DiariesAPI extends Collection {
12 | items: Diaries;
13 | }
14 |
--------------------------------------------------------------------------------
/ch7/gym-diary-backend/src/exercises/dto/create-exercises.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiPropertyOptional } from '@nestjs/swagger';
2 | import { Exercise } from '../interface/exercises.interface';
3 |
4 | export class CreateExercisesDto implements Exercise {
5 | @ApiPropertyOptional()
6 | id: string;
7 |
8 | @ApiPropertyOptional()
9 | description: string;
10 | }
11 |
--------------------------------------------------------------------------------
/ch7/gym-diary-backend/src/exercises/interface/exercises.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Exercises = Array;
4 | export interface Exercise extends Item {
5 | description?: string;
6 | }
7 |
8 | export interface ExercisesAPI extends Collection {
9 | items: Exercises;
10 | }
11 |
--------------------------------------------------------------------------------
/ch7/gym-diary-backend/src/users/db/users.data.ts:
--------------------------------------------------------------------------------
1 | import { Users } from '../interface/users.interface';
2 |
3 | export const users: Users = [
4 | {
5 | id: '1',
6 | username: 'mario',
7 | password: '1234',
8 | name: 'mario',
9 | },
10 | {
11 | id: '2',
12 | username: 'gabriel',
13 | password: '1234',
14 | name: 'gabriel',
15 | },
16 | ];
17 |
--------------------------------------------------------------------------------
/ch7/gym-diary-backend/src/users/interface/users.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Users = Array;
4 | export interface User extends Item {
5 | username?: string;
6 | password?: string;
7 | name?: string;
8 | }
9 |
10 | export interface UsersAPI extends Collection {
11 | items: Users;
12 | }
13 |
--------------------------------------------------------------------------------
/ch7/gym-diary-backend/src/utils/interfaces/collection.interface.ts:
--------------------------------------------------------------------------------
1 | export interface Collection {
2 | hasNext?: boolean;
3 | items: Items;
4 | }
5 |
6 | export interface Item {
7 | id?: string;
8 | }
9 |
10 | export type Items = Array
- ;
11 |
--------------------------------------------------------------------------------
/ch7/gym-diary-backend/src/utils/interfaces/error.interface.ts:
--------------------------------------------------------------------------------
1 | export interface Error {
2 | code: 'string';
3 | message: 'string';
4 | detailedMessage: 'string';
5 | helpUrl: 'string';
6 | details: 'string';
7 | }
8 |
--------------------------------------------------------------------------------
/ch7/gym-diary-backend/src/utils/interfaces/query.interface.ts:
--------------------------------------------------------------------------------
1 | export interface QueryApi {
2 | search?: string;
3 | filter?: string;
4 | page?: string;
5 | pageSize?: string;
6 | }
7 |
8 | export interface ParamQueryId {
9 | id?: string;
10 | }
11 |
--------------------------------------------------------------------------------
/ch7/gym-diary-backend/test/jest-e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "moduleFileExtensions": ["js", "json", "ts"],
3 | "rootDir": ".",
4 | "testEnvironment": "node",
5 | "testRegex": ".e2e-spec.ts$",
6 | "transform": {
7 | "^.+\\.(t|j)s$": "ts-jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ch7/gym-diary-backend/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch7/gym-diary/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/ch7/gym-diary/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3 | "recommendations": ["angular.ng-template"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch7/gym-diary/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [require('prettier-plugin-tailwindcss')],
3 | tailwindConfig: './tailwind.config.js',
4 | }
--------------------------------------------------------------------------------
/ch7/gym-diary/src/app/app.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch7/gym-diary/src/app/app.component.css
--------------------------------------------------------------------------------
/ch7/gym-diary/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/ch7/gym-diary/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-root',
5 | templateUrl: './app.component.html',
6 | styleUrls: ['./app.component.css']
7 | })
8 | export class AppComponent {
9 | title = 'gym-diary';
10 | }
11 |
--------------------------------------------------------------------------------
/ch7/gym-diary/src/app/diary/diary/diary.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch7/gym-diary/src/app/diary/diary/diary.component.css
--------------------------------------------------------------------------------
/ch7/gym-diary/src/app/diary/entry-item/entry-item.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch7/gym-diary/src/app/diary/entry-item/entry-item.component.css
--------------------------------------------------------------------------------
/ch7/gym-diary/src/app/diary/interfaces/exercise-set.ts:
--------------------------------------------------------------------------------
1 | export interface ExerciseSet {
2 | id?: string;
3 | date: Date;
4 | exercise: string;
5 | sets: number;
6 | reps: number;
7 | }
8 |
9 | export type ExerciseSetList = Array;
10 |
11 | export interface ExerciseSetListAPI {
12 | hasNext: boolean;
13 | items: ExerciseSetList;
14 | }
15 |
--------------------------------------------------------------------------------
/ch7/gym-diary/src/app/diary/list-entries/list-entries.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch7/gym-diary/src/app/diary/list-entries/list-entries.component.css
--------------------------------------------------------------------------------
/ch7/gym-diary/src/app/diary/new-entry-form-reactive/new-entry-form-reactive.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch7/gym-diary/src/app/diary/new-entry-form-reactive/new-entry-form-reactive.component.css
--------------------------------------------------------------------------------
/ch7/gym-diary/src/app/diary/new-entry-form-template/new-entry-form-template.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch7/gym-diary/src/app/diary/new-entry-form-template/new-entry-form-template.component.css
--------------------------------------------------------------------------------
/ch7/gym-diary/src/app/diary/new-item-button/new-item-button.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch7/gym-diary/src/app/diary/new-item-button/new-item-button.component.css
--------------------------------------------------------------------------------
/ch7/gym-diary/src/app/diary/new-item-button/new-item-button.component.html:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/ch7/gym-diary/src/app/error-page/error-page.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch7/gym-diary/src/app/error-page/error-page.component.css
--------------------------------------------------------------------------------
/ch7/gym-diary/src/app/error-page/error-page.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-error-page',
5 | templateUrl: './error-page.component.html',
6 | styleUrls: ['./error-page.component.css']
7 | })
8 | export class ErrorPageComponent {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/ch7/gym-diary/src/app/home/home.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch7/gym-diary/src/app/home/home.component.css
--------------------------------------------------------------------------------
/ch7/gym-diary/src/app/home/home.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 |
4 | import { HomeRoutingModule } from './home-routing.module';
5 | import { HomeComponent } from './home.component';
6 |
7 | @NgModule({
8 | declarations: [HomeComponent],
9 | imports: [CommonModule, HomeRoutingModule],
10 | })
11 | export class HomeModule {}
12 |
--------------------------------------------------------------------------------
/ch7/gym-diary/src/app/login/auth.ts:
--------------------------------------------------------------------------------
1 | export interface LoginForm {
2 | username: string;
3 | password: string;
4 | }
5 |
6 | export interface Token {
7 | access_token: string;
8 | }
9 |
--------------------------------------------------------------------------------
/ch7/gym-diary/src/app/login/login.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch7/gym-diary/src/app/login/login.component.css
--------------------------------------------------------------------------------
/ch7/gym-diary/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch7/gym-diary/src/assets/.gitkeep
--------------------------------------------------------------------------------
/ch7/gym-diary/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch7/gym-diary/src/favicon.ico
--------------------------------------------------------------------------------
/ch7/gym-diary/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | GymDiary
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch7/gym-diary/src/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
2 |
3 | import { AppModule } from './app/app.module';
4 |
5 |
6 | platformBrowserDynamic().bootstrapModule(AppModule)
7 | .catch(err => console.error(err));
8 |
--------------------------------------------------------------------------------
/ch7/gym-diary/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 | @tailwind base;
3 | @tailwind components;
4 | @tailwind utilities;
--------------------------------------------------------------------------------
/ch7/gym-diary/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./src/**/*.{html,ts}",
5 | ],
6 | theme: {
7 | extend: {},
8 | },
9 | plugins: [],
10 | }
11 |
--------------------------------------------------------------------------------
/ch7/gym-diary/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts"
10 | ],
11 | "include": [
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch7/gym-diary/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "include": [
11 | "src/**/*.spec.ts",
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch8/gym-diary-backend/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all"
4 | }
--------------------------------------------------------------------------------
/ch8/gym-diary-backend/nest-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/nest-cli",
3 | "collection": "@nestjs/schematics",
4 | "sourceRoot": "src",
5 | "compilerOptions": {
6 | "deleteOutDir": true
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch8/gym-diary-backend/src/app.controller.ts:
--------------------------------------------------------------------------------
1 | import { Controller } from '@nestjs/common';
2 |
3 | @Controller()
4 | export class AppController {}
5 |
--------------------------------------------------------------------------------
/ch8/gym-diary-backend/src/app.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 |
3 | @Injectable()
4 | export class AppService {
5 | getHello(): string {
6 | return 'Hello World!';
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch8/gym-diary-backend/src/auth/constants.ts:
--------------------------------------------------------------------------------
1 | export const jwtConstants = {
2 | secret:
3 | 'DO NOT USE THIS VALUE. INSTEAD, CREATE A COMPLEX SECRET AND KEEP IT SAFE OUTSIDE OF THE SOURCE CODE.',
4 | };
5 |
--------------------------------------------------------------------------------
/ch8/gym-diary-backend/src/auth/public.decorator.ts:
--------------------------------------------------------------------------------
1 | import { SetMetadata } from '@nestjs/common';
2 |
3 | export const IS_PUBLIC_KEY = 'isPublic';
4 | export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
5 |
--------------------------------------------------------------------------------
/ch8/gym-diary-backend/src/diary/interface/diary.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Diaries = Array;
4 | export interface Diary extends Item {
5 | date?: string;
6 | exercise?: string;
7 | sets?: number;
8 | reps?: number;
9 | }
10 |
11 | export interface DiariesAPI extends Collection {
12 | items: Diaries;
13 | }
14 |
--------------------------------------------------------------------------------
/ch8/gym-diary-backend/src/exercises/dto/create-exercises.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiPropertyOptional } from '@nestjs/swagger';
2 | import { Exercise } from '../interface/exercises.interface';
3 |
4 | export class CreateExercisesDto implements Exercise {
5 | @ApiPropertyOptional()
6 | id: string;
7 |
8 | @ApiPropertyOptional()
9 | description: string;
10 | }
11 |
--------------------------------------------------------------------------------
/ch8/gym-diary-backend/src/exercises/interface/exercises.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Exercises = Array;
4 | export interface Exercise extends Item {
5 | description?: string;
6 | }
7 |
8 | export interface ExercisesAPI extends Collection {
9 | items: Exercises;
10 | }
11 |
--------------------------------------------------------------------------------
/ch8/gym-diary-backend/src/users/db/users.data.ts:
--------------------------------------------------------------------------------
1 | import { Users } from '../interface/users.interface';
2 |
3 | export const users: Users = [
4 | {
5 | id: '1',
6 | username: 'mario',
7 | password: '1234',
8 | name: 'mario',
9 | },
10 | {
11 | id: '2',
12 | username: 'gabriel',
13 | password: '1234',
14 | name: 'gabriel',
15 | },
16 | ];
17 |
--------------------------------------------------------------------------------
/ch8/gym-diary-backend/src/users/interface/users.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Users = Array;
4 | export interface User extends Item {
5 | username?: string;
6 | password?: string;
7 | name?: string;
8 | }
9 |
10 | export interface UsersAPI extends Collection {
11 | items: Users;
12 | }
13 |
--------------------------------------------------------------------------------
/ch8/gym-diary-backend/src/utils/interfaces/collection.interface.ts:
--------------------------------------------------------------------------------
1 | export interface Collection {
2 | hasNext?: boolean;
3 | items: Items;
4 | }
5 |
6 | export interface Item {
7 | id?: string;
8 | }
9 |
10 | export type Items = Array
- ;
11 |
--------------------------------------------------------------------------------
/ch8/gym-diary-backend/src/utils/interfaces/error.interface.ts:
--------------------------------------------------------------------------------
1 | export interface Error {
2 | code: 'string';
3 | message: 'string';
4 | detailedMessage: 'string';
5 | helpUrl: 'string';
6 | details: 'string';
7 | }
8 |
--------------------------------------------------------------------------------
/ch8/gym-diary-backend/src/utils/interfaces/query.interface.ts:
--------------------------------------------------------------------------------
1 | export interface QueryApi {
2 | search?: string;
3 | filter?: string;
4 | page?: string;
5 | pageSize?: string;
6 | }
7 |
8 | export interface ParamQueryId {
9 | id?: string;
10 | }
11 |
--------------------------------------------------------------------------------
/ch8/gym-diary-backend/test/jest-e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "moduleFileExtensions": ["js", "json", "ts"],
3 | "rootDir": ".",
4 | "testEnvironment": "node",
5 | "testRegex": ".e2e-spec.ts$",
6 | "transform": {
7 | "^.+\\.(t|j)s$": "ts-jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ch8/gym-diary-backend/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch8/gym-diary/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/ch8/gym-diary/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3 | "recommendations": ["angular.ng-template"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch8/gym-diary/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [require('prettier-plugin-tailwindcss')],
3 | tailwindConfig: './tailwind.config.js',
4 | }
--------------------------------------------------------------------------------
/ch8/gym-diary/src/app/app.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch8/gym-diary/src/app/app.component.css
--------------------------------------------------------------------------------
/ch8/gym-diary/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/ch8/gym-diary/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, inject } from '@angular/core';
2 | import { LoadService } from './loading-overlay/load.service';
3 |
4 | @Component({
5 | selector: 'app-root',
6 | templateUrl: './app.component.html',
7 | styleUrls: ['./app.component.css'],
8 | })
9 | export class AppComponent {
10 | loadService = inject(LoadService);
11 | title = 'gym-diary';
12 | }
13 |
--------------------------------------------------------------------------------
/ch8/gym-diary/src/app/diary/diary/diary.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch8/gym-diary/src/app/diary/diary/diary.component.css
--------------------------------------------------------------------------------
/ch8/gym-diary/src/app/diary/entry-item/entry-item.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch8/gym-diary/src/app/diary/entry-item/entry-item.component.css
--------------------------------------------------------------------------------
/ch8/gym-diary/src/app/diary/interfaces/exercise-set.ts:
--------------------------------------------------------------------------------
1 | export interface ExerciseSet {
2 | id?: string;
3 | date: Date;
4 | exercise: string;
5 | sets: number;
6 | reps: number;
7 | }
8 |
9 | export type ExerciseSetList = Array;
10 |
11 | export interface ExerciseSetListAPI {
12 | hasNext: boolean;
13 | items: ExerciseSetList;
14 | }
15 |
--------------------------------------------------------------------------------
/ch8/gym-diary/src/app/diary/list-entries/list-entries.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch8/gym-diary/src/app/diary/list-entries/list-entries.component.css
--------------------------------------------------------------------------------
/ch8/gym-diary/src/app/diary/new-entry-form-reactive/new-entry-form-reactive.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch8/gym-diary/src/app/diary/new-entry-form-reactive/new-entry-form-reactive.component.css
--------------------------------------------------------------------------------
/ch8/gym-diary/src/app/diary/new-entry-form-template/new-entry-form-template.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch8/gym-diary/src/app/diary/new-entry-form-template/new-entry-form-template.component.css
--------------------------------------------------------------------------------
/ch8/gym-diary/src/app/diary/new-item-button/new-item-button.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch8/gym-diary/src/app/diary/new-item-button/new-item-button.component.css
--------------------------------------------------------------------------------
/ch8/gym-diary/src/app/diary/new-item-button/new-item-button.component.html:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/ch8/gym-diary/src/app/error-page/error-page.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch8/gym-diary/src/app/error-page/error-page.component.css
--------------------------------------------------------------------------------
/ch8/gym-diary/src/app/error-page/error-page.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-error-page',
5 | templateUrl: './error-page.component.html',
6 | styleUrls: ['./error-page.component.css']
7 | })
8 | export class ErrorPageComponent {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/ch8/gym-diary/src/app/home/home.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch8/gym-diary/src/app/home/home.component.css
--------------------------------------------------------------------------------
/ch8/gym-diary/src/app/home/home.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 |
4 | import { HomeRoutingModule } from './home-routing.module';
5 | import { HomeComponent } from './home.component';
6 |
7 | @NgModule({
8 | declarations: [HomeComponent],
9 | imports: [CommonModule, HomeRoutingModule],
10 | })
11 | export class HomeModule {}
12 |
--------------------------------------------------------------------------------
/ch8/gym-diary/src/app/loading-overlay/loading-overlay.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch8/gym-diary/src/app/loading-overlay/loading-overlay.component.css
--------------------------------------------------------------------------------
/ch8/gym-diary/src/app/loading-overlay/loading-overlay.component.html:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/ch8/gym-diary/src/app/loading-overlay/loading-overlay.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-loading-overlay',
5 | templateUrl: './loading-overlay.component.html',
6 | styleUrls: ['./loading-overlay.component.css']
7 | })
8 | export class LoadingOverlayComponent {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/ch8/gym-diary/src/app/login/auth.ts:
--------------------------------------------------------------------------------
1 | export interface LoginForm {
2 | username: string;
3 | password: string;
4 | }
5 |
6 | export interface Token {
7 | access_token: string;
8 | }
9 |
--------------------------------------------------------------------------------
/ch8/gym-diary/src/app/login/login.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch8/gym-diary/src/app/login/login.component.css
--------------------------------------------------------------------------------
/ch8/gym-diary/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch8/gym-diary/src/assets/.gitkeep
--------------------------------------------------------------------------------
/ch8/gym-diary/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch8/gym-diary/src/favicon.ico
--------------------------------------------------------------------------------
/ch8/gym-diary/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | GymDiary
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch8/gym-diary/src/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
2 |
3 | import { AppModule } from './app/app.module';
4 |
5 |
6 | platformBrowserDynamic().bootstrapModule(AppModule)
7 | .catch(err => console.error(err));
8 |
--------------------------------------------------------------------------------
/ch8/gym-diary/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 | @tailwind base;
3 | @tailwind components;
4 | @tailwind utilities;
--------------------------------------------------------------------------------
/ch8/gym-diary/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./src/**/*.{html,ts}",
5 | ],
6 | theme: {
7 | extend: {},
8 | },
9 | plugins: [],
10 | }
11 |
--------------------------------------------------------------------------------
/ch8/gym-diary/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts"
10 | ],
11 | "include": [
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch8/gym-diary/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "include": [
11 | "src/**/*.spec.ts",
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch9/gym-diary-backend/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all"
4 | }
--------------------------------------------------------------------------------
/ch9/gym-diary-backend/nest-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/nest-cli",
3 | "collection": "@nestjs/schematics",
4 | "sourceRoot": "src",
5 | "compilerOptions": {
6 | "deleteOutDir": true
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch9/gym-diary-backend/src/app.controller.ts:
--------------------------------------------------------------------------------
1 | import { Controller } from '@nestjs/common';
2 |
3 | @Controller()
4 | export class AppController {}
5 |
--------------------------------------------------------------------------------
/ch9/gym-diary-backend/src/app.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 |
3 | @Injectable()
4 | export class AppService {
5 | getHello(): string {
6 | return 'Hello World!';
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/ch9/gym-diary-backend/src/auth/constants.ts:
--------------------------------------------------------------------------------
1 | export const jwtConstants = {
2 | secret:
3 | 'DO NOT USE THIS VALUE. INSTEAD, CREATE A COMPLEX SECRET AND KEEP IT SAFE OUTSIDE OF THE SOURCE CODE.',
4 | };
5 |
--------------------------------------------------------------------------------
/ch9/gym-diary-backend/src/auth/public.decorator.ts:
--------------------------------------------------------------------------------
1 | import { SetMetadata } from '@nestjs/common';
2 |
3 | export const IS_PUBLIC_KEY = 'isPublic';
4 | export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
5 |
--------------------------------------------------------------------------------
/ch9/gym-diary-backend/src/diary/interface/diary.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Diaries = Array;
4 | export interface Diary extends Item {
5 | date?: string;
6 | exercise?: string;
7 | sets?: number;
8 | reps?: number;
9 | }
10 |
11 | export interface DiariesAPI extends Collection {
12 | items: Diaries;
13 | }
14 |
--------------------------------------------------------------------------------
/ch9/gym-diary-backend/src/exercises/dto/create-exercises.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiPropertyOptional } from '@nestjs/swagger';
2 | import { Exercise } from '../interface/exercises.interface';
3 |
4 | export class CreateExercisesDto implements Exercise {
5 | @ApiPropertyOptional()
6 | id: string;
7 |
8 | @ApiPropertyOptional()
9 | description: string;
10 | }
11 |
--------------------------------------------------------------------------------
/ch9/gym-diary-backend/src/exercises/interface/exercises.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Exercises = Array;
4 | export interface Exercise extends Item {
5 | description?: string;
6 | }
7 |
8 | export interface ExercisesAPI extends Collection {
9 | items: Exercises;
10 | }
11 |
--------------------------------------------------------------------------------
/ch9/gym-diary-backend/src/users/db/users.data.ts:
--------------------------------------------------------------------------------
1 | import { Users } from '../interface/users.interface';
2 |
3 | export const users: Users = [
4 | {
5 | id: '1',
6 | username: 'mario',
7 | password: '1234',
8 | name: 'mario',
9 | },
10 | {
11 | id: '2',
12 | username: 'gabriel',
13 | password: '1234',
14 | name: 'gabriel',
15 | },
16 | ];
17 |
--------------------------------------------------------------------------------
/ch9/gym-diary-backend/src/users/interface/users.interface.ts:
--------------------------------------------------------------------------------
1 | import { Collection, Item } from '../../utils/interfaces/collection.interface';
2 |
3 | export type Users = Array;
4 | export interface User extends Item {
5 | username?: string;
6 | password?: string;
7 | name?: string;
8 | }
9 |
10 | export interface UsersAPI extends Collection {
11 | items: Users;
12 | }
13 |
--------------------------------------------------------------------------------
/ch9/gym-diary-backend/src/utils/interfaces/collection.interface.ts:
--------------------------------------------------------------------------------
1 | export interface Collection {
2 | hasNext?: boolean;
3 | items: Items;
4 | }
5 |
6 | export interface Item {
7 | id?: string;
8 | }
9 |
10 | export type Items = Array
- ;
11 |
--------------------------------------------------------------------------------
/ch9/gym-diary-backend/src/utils/interfaces/error.interface.ts:
--------------------------------------------------------------------------------
1 | export interface Error {
2 | code: 'string';
3 | message: 'string';
4 | detailedMessage: 'string';
5 | helpUrl: 'string';
6 | details: 'string';
7 | }
8 |
--------------------------------------------------------------------------------
/ch9/gym-diary-backend/src/utils/interfaces/query.interface.ts:
--------------------------------------------------------------------------------
1 | export interface QueryApi {
2 | search?: string;
3 | filter?: string;
4 | page?: string;
5 | pageSize?: string;
6 | }
7 |
8 | export interface ParamQueryId {
9 | id?: string;
10 | }
11 |
--------------------------------------------------------------------------------
/ch9/gym-diary-backend/test/jest-e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "moduleFileExtensions": ["js", "json", "ts"],
3 | "rootDir": ".",
4 | "testEnvironment": "node",
5 | "testRegex": ".e2e-spec.ts$",
6 | "transform": {
7 | "^.+\\.(t|j)s$": "ts-jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/ch9/gym-diary-backend/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch9/gym-diary/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/ch9/gym-diary/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3 | "recommendations": ["angular.ng-template"]
4 | }
5 |
--------------------------------------------------------------------------------
/ch9/gym-diary/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [require('prettier-plugin-tailwindcss')],
3 | tailwindConfig: './tailwind.config.js',
4 | }
--------------------------------------------------------------------------------
/ch9/gym-diary/src/app/app.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch9/gym-diary/src/app/app.component.css
--------------------------------------------------------------------------------
/ch9/gym-diary/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/ch9/gym-diary/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, inject } from '@angular/core';
2 | import { LoadService } from './loading-overlay/load.service';
3 |
4 | @Component({
5 | selector: 'app-root',
6 | templateUrl: './app.component.html',
7 | styleUrls: ['./app.component.css'],
8 | })
9 | export class AppComponent {
10 | loadService = inject(LoadService);
11 | title = 'gym-diary';
12 | }
13 |
--------------------------------------------------------------------------------
/ch9/gym-diary/src/app/diary/diary/diary.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch9/gym-diary/src/app/diary/diary/diary.component.css
--------------------------------------------------------------------------------
/ch9/gym-diary/src/app/diary/entry-item/entry-item.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch9/gym-diary/src/app/diary/entry-item/entry-item.component.css
--------------------------------------------------------------------------------
/ch9/gym-diary/src/app/diary/interfaces/exercise-set.ts:
--------------------------------------------------------------------------------
1 | export interface ExerciseSet {
2 | id?: string;
3 | date: Date;
4 | exercise: string;
5 | sets: number;
6 | reps: number;
7 | }
8 |
9 | export type ExerciseSetList = Array;
10 |
11 | export interface ExerciseSetListAPI {
12 | hasNext: boolean;
13 | items: ExerciseSetList;
14 | }
15 |
--------------------------------------------------------------------------------
/ch9/gym-diary/src/app/diary/interfaces/exercise.ts:
--------------------------------------------------------------------------------
1 | export interface Exercise {
2 | id?: string;
3 | description: string;
4 | }
5 |
6 | export type ExerciseList = Array;
7 |
8 | export interface ExerciseListAPI {
9 | hasNext: boolean;
10 | items: ExerciseList;
11 | }
12 |
--------------------------------------------------------------------------------
/ch9/gym-diary/src/app/diary/list-entries/list-entries.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch9/gym-diary/src/app/diary/list-entries/list-entries.component.css
--------------------------------------------------------------------------------
/ch9/gym-diary/src/app/diary/new-entry-form-reactive/new-entry-form-reactive.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch9/gym-diary/src/app/diary/new-entry-form-reactive/new-entry-form-reactive.component.css
--------------------------------------------------------------------------------
/ch9/gym-diary/src/app/diary/new-entry-form-template/new-entry-form-template.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch9/gym-diary/src/app/diary/new-entry-form-template/new-entry-form-template.component.css
--------------------------------------------------------------------------------
/ch9/gym-diary/src/app/diary/new-item-button/new-item-button.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch9/gym-diary/src/app/diary/new-item-button/new-item-button.component.css
--------------------------------------------------------------------------------
/ch9/gym-diary/src/app/diary/new-item-button/new-item-button.component.html:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/ch9/gym-diary/src/app/error-page/error-page.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch9/gym-diary/src/app/error-page/error-page.component.css
--------------------------------------------------------------------------------
/ch9/gym-diary/src/app/error-page/error-page.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-error-page',
5 | templateUrl: './error-page.component.html',
6 | styleUrls: ['./error-page.component.css']
7 | })
8 | export class ErrorPageComponent {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/ch9/gym-diary/src/app/home/home.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch9/gym-diary/src/app/home/home.component.css
--------------------------------------------------------------------------------
/ch9/gym-diary/src/app/home/home.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 |
4 | import { HomeRoutingModule } from './home-routing.module';
5 | import { HomeComponent } from './home.component';
6 |
7 | @NgModule({
8 | declarations: [HomeComponent],
9 | imports: [CommonModule, HomeRoutingModule],
10 | })
11 | export class HomeModule {}
12 |
--------------------------------------------------------------------------------
/ch9/gym-diary/src/app/loading-overlay/loading-overlay.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch9/gym-diary/src/app/loading-overlay/loading-overlay.component.css
--------------------------------------------------------------------------------
/ch9/gym-diary/src/app/loading-overlay/loading-overlay.component.html:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/ch9/gym-diary/src/app/loading-overlay/loading-overlay.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-loading-overlay',
5 | templateUrl: './loading-overlay.component.html',
6 | styleUrls: ['./loading-overlay.component.css']
7 | })
8 | export class LoadingOverlayComponent {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/ch9/gym-diary/src/app/login/auth.ts:
--------------------------------------------------------------------------------
1 | export interface LoginForm {
2 | username: string;
3 | password: string;
4 | }
5 |
6 | export interface Token {
7 | access_token: string;
8 | }
9 |
--------------------------------------------------------------------------------
/ch9/gym-diary/src/app/login/login.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch9/gym-diary/src/app/login/login.component.css
--------------------------------------------------------------------------------
/ch9/gym-diary/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch9/gym-diary/src/assets/.gitkeep
--------------------------------------------------------------------------------
/ch9/gym-diary/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Angular-Design-Patterns-and-Best-Practices/d1fb33b32f972d803cdde241b58e2b8b8f137f26/ch9/gym-diary/src/favicon.ico
--------------------------------------------------------------------------------
/ch9/gym-diary/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | GymDiary
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ch9/gym-diary/src/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
2 |
3 | import { AppModule } from './app/app.module';
4 |
5 |
6 | platformBrowserDynamic().bootstrapModule(AppModule)
7 | .catch(err => console.error(err));
8 |
--------------------------------------------------------------------------------
/ch9/gym-diary/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 | @tailwind base;
3 | @tailwind components;
4 | @tailwind utilities;
--------------------------------------------------------------------------------
/ch9/gym-diary/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./src/**/*.{html,ts}",
5 | ],
6 | theme: {
7 | extend: {},
8 | },
9 | plugins: [],
10 | }
11 |
--------------------------------------------------------------------------------
/ch9/gym-diary/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts"
10 | ],
11 | "include": [
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ch9/gym-diary/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "include": [
11 | "src/**/*.spec.ts",
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------