├── 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 |
4 |
Loading...
5 |
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 |
4 |
Loading...
5 |
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 |
4 |
Loading...
5 |
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 |
4 |
Loading...
5 |
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 |
4 |
Loading...
5 |
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 |
4 |
Loading...
5 |
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 | --------------------------------------------------------------------------------