From 3cea14982ed1c0ae09b2b4abee634e382b65822b Mon Sep 17 00:00:00 2001 From: thomas Date: Wed, 29 Jan 2025 20:25:35 +0100 Subject: [PATCH] feat(rxjs): refactor challenge 11 --- apps/ngrx/2-effect-vs-selector/.eslintrc.json | 36 --- apps/ngrx/2-effect-vs-selector/README.md | 13 - apps/ngrx/2-effect-vs-selector/jest.config.ts | 23 -- apps/ngrx/2-effect-vs-selector/project.json | 84 ------- .../src/app/app.component.ts | 71 ------ .../src/app/app.config.ts | 27 -- .../app/store/activity/activity.actions.ts | 14 -- .../app/store/activity/activity.effects.ts | 30 --- .../src/app/store/activity/activity.model.ts | 55 ----- .../app/store/activity/activity.reducer.ts | 25 -- .../app/store/activity/activity.selectors.ts | 10 - .../app/store/activity/activity.service.ts | 10 - .../src/app/store/status/status.actions.ts | 9 - .../src/app/store/status/status.effects.ts | 52 ---- .../src/app/store/status/status.model.ts | 6 - .../src/app/store/status/status.reducer.ts | 29 --- .../src/app/store/status/status.selectors.ts | 17 -- .../src/app/store/user/user.actions.ts | 14 -- .../src/app/store/user/user.effects.ts | 26 -- .../src/app/store/user/user.model.ts | 15 -- .../src/app/store/user/user.reducer.ts | 19 -- .../src/app/store/user/user.selectors.ts | 9 - .../src/app/store/user/user.service.ts | 10 - .../2-effect-vs-selector/src/assets/.gitkeep | 0 .../ngrx/2-effect-vs-selector/src/favicon.ico | Bin 15086 -> 0 bytes apps/ngrx/2-effect-vs-selector/src/index.html | 13 - apps/ngrx/2-effect-vs-selector/src/main.ts | 6 - .../2-effect-vs-selector/src/polyfills.ts | 52 ---- .../ngrx/2-effect-vs-selector/src/styles.scss | 0 .../2-effect-vs-selector/src/test-setup.ts | 1 - .../2-effect-vs-selector/tsconfig.app.json | 12 - .../2-effect-vs-selector/tsconfig.editor.json | 7 - apps/ngrx/2-effect-vs-selector/tsconfig.json | 31 --- .../2-effect-vs-selector/tsconfig.spec.json | 10 - apps/ngrx/7-power-of-effect/.eslintrc.json | 36 --- apps/ngrx/7-power-of-effect/README.md | 13 - apps/ngrx/7-power-of-effect/project.json | 76 ------ .../7-power-of-effect/src/app/app.actions.ts | 9 - .../src/app/app.component.ts | 39 --- .../7-power-of-effect/src/app/app.config.ts | 50 ---- .../src/app/data-access/http.service.ts | 14 -- .../app/data-access/notification.service.ts | 39 --- apps/ngrx/7-power-of-effect/src/app/routes.ts | 20 -- .../src/app/school/school.component.ts | 32 --- .../src/app/school/school.store.ts | 45 ---- .../src/app/student/store/student.actions.ts | 10 - .../src/app/student/store/student.effects.ts | 23 -- .../src/app/student/store/student.reducer.ts | 24 -- .../app/student/store/student.selectors.ts | 17 -- .../src/app/student/student.component.ts | 31 --- .../src/app/teacher/store/teacher.actions.ts | 10 - .../src/app/teacher/store/teacher.effects.ts | 23 -- .../src/app/teacher/store/teacher.reducer.ts | 24 -- .../app/teacher/store/teacher.selectors.ts | 17 -- .../src/app/teacher/teacher.component.ts | 32 --- .../7-power-of-effect/src/assets/.gitkeep | 0 apps/ngrx/7-power-of-effect/src/favicon.ico | Bin 15086 -> 0 bytes apps/ngrx/7-power-of-effect/src/index.html | 13 - apps/ngrx/7-power-of-effect/src/main.ts | 9 - apps/ngrx/7-power-of-effect/src/polyfills.ts | 52 ---- apps/ngrx/7-power-of-effect/src/styles.scss | 1 - apps/ngrx/7-power-of-effect/tsconfig.app.json | 12 - .../7-power-of-effect/tsconfig.editor.json | 10 - apps/ngrx/7-power-of-effect/tsconfig.json | 28 --- .../src/app/app.component.ts | 32 ++- .../src/app/app.service.ts | 20 +- .../src/app/localDB.service.ts | 21 +- .../docs/challenges/ngrx/2-effect-selector.md | 40 --- .../docs/challenges/ngrx/7-power-effect.md | 46 ---- libs/power-of-effect/backend/.eslintrc.json | 36 --- libs/power-of-effect/backend/README.md | 7 - libs/power-of-effect/backend/jest.config.ts | 23 -- libs/power-of-effect/backend/project.json | 21 -- libs/power-of-effect/backend/src/index.ts | 2 - .../backend/src/lib/fake-backend.service.ts | 105 -------- .../backend/src/lib/fake-db.service.ts | 81 ------ .../backend/src/lib/push.service.ts | 15 -- .../power-of-effect/backend/src/test-setup.ts | 1 - libs/power-of-effect/backend/tsconfig.json | 28 --- .../power-of-effect/backend/tsconfig.lib.json | 17 -- .../backend/tsconfig.spec.json | 10 - libs/power-of-effect/model/.eslintrc.json | 36 --- libs/power-of-effect/model/README.md | 7 - libs/power-of-effect/model/jest.config.ts | 23 -- libs/power-of-effect/model/project.json | 21 -- libs/power-of-effect/model/src/index.ts | 4 - .../model/src/lib/push.model.ts | 5 - .../model/src/lib/school.model.ts | 21 -- .../model/src/lib/student.model.ts | 23 -- .../model/src/lib/teacher.model.ts | 23 -- libs/power-of-effect/model/src/test-setup.ts | 1 - libs/power-of-effect/model/tsconfig.json | 28 --- libs/power-of-effect/model/tsconfig.lib.json | 17 -- libs/power-of-effect/model/tsconfig.spec.json | 10 - .../ngrx-callstate-store/.eslintrc.json | 36 --- libs/shared/ngrx-callstate-store/README.md | 231 ------------------ .../ngrx-callstate-store/jest.config.ts | 23 -- .../ngrx-callstate-store/ng-package.json | 7 - libs/shared/ngrx-callstate-store/package.json | 27 -- libs/shared/ngrx-callstate-store/project.json | 37 --- libs/shared/ngrx-callstate-store/src/index.ts | 2 - .../src/lib/call-state-component-store.ts | 105 -------- .../src/lib/call-state.model.ts | 51 ---- .../src/lib/external.model.ts | 32 --- .../src/lib/non-flicker-loader.ts | 20 -- .../ngrx-callstate-store/src/test-setup.ts | 1 - .../shared/ngrx-callstate-store/tsconfig.json | 32 --- .../ngrx-callstate-store/tsconfig.lib.json | 17 -- .../tsconfig.lib.prod.json | 9 - .../ngrx-callstate-store/tsconfig.spec.json | 10 - tsconfig.base.json | 9 - 111 files changed, 31 insertions(+), 2787 deletions(-) delete mode 100644 apps/ngrx/2-effect-vs-selector/.eslintrc.json delete mode 100644 apps/ngrx/2-effect-vs-selector/README.md delete mode 100644 apps/ngrx/2-effect-vs-selector/jest.config.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/project.json delete mode 100644 apps/ngrx/2-effect-vs-selector/src/app/app.component.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/src/app/app.config.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.actions.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.effects.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.model.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.reducer.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.selectors.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.service.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/src/app/store/status/status.actions.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/src/app/store/status/status.effects.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/src/app/store/status/status.model.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/src/app/store/status/status.reducer.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/src/app/store/status/status.selectors.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/src/app/store/user/user.actions.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/src/app/store/user/user.effects.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/src/app/store/user/user.model.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/src/app/store/user/user.reducer.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/src/app/store/user/user.selectors.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/src/app/store/user/user.service.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/src/assets/.gitkeep delete mode 100644 apps/ngrx/2-effect-vs-selector/src/favicon.ico delete mode 100644 apps/ngrx/2-effect-vs-selector/src/index.html delete mode 100644 apps/ngrx/2-effect-vs-selector/src/main.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/src/polyfills.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/src/styles.scss delete mode 100644 apps/ngrx/2-effect-vs-selector/src/test-setup.ts delete mode 100644 apps/ngrx/2-effect-vs-selector/tsconfig.app.json delete mode 100644 apps/ngrx/2-effect-vs-selector/tsconfig.editor.json delete mode 100644 apps/ngrx/2-effect-vs-selector/tsconfig.json delete mode 100644 apps/ngrx/2-effect-vs-selector/tsconfig.spec.json delete mode 100644 apps/ngrx/7-power-of-effect/.eslintrc.json delete mode 100644 apps/ngrx/7-power-of-effect/README.md delete mode 100644 apps/ngrx/7-power-of-effect/project.json delete mode 100644 apps/ngrx/7-power-of-effect/src/app/app.actions.ts delete mode 100644 apps/ngrx/7-power-of-effect/src/app/app.component.ts delete mode 100644 apps/ngrx/7-power-of-effect/src/app/app.config.ts delete mode 100644 apps/ngrx/7-power-of-effect/src/app/data-access/http.service.ts delete mode 100644 apps/ngrx/7-power-of-effect/src/app/data-access/notification.service.ts delete mode 100644 apps/ngrx/7-power-of-effect/src/app/routes.ts delete mode 100644 apps/ngrx/7-power-of-effect/src/app/school/school.component.ts delete mode 100644 apps/ngrx/7-power-of-effect/src/app/school/school.store.ts delete mode 100644 apps/ngrx/7-power-of-effect/src/app/student/store/student.actions.ts delete mode 100644 apps/ngrx/7-power-of-effect/src/app/student/store/student.effects.ts delete mode 100644 apps/ngrx/7-power-of-effect/src/app/student/store/student.reducer.ts delete mode 100644 apps/ngrx/7-power-of-effect/src/app/student/store/student.selectors.ts delete mode 100644 apps/ngrx/7-power-of-effect/src/app/student/student.component.ts delete mode 100644 apps/ngrx/7-power-of-effect/src/app/teacher/store/teacher.actions.ts delete mode 100644 apps/ngrx/7-power-of-effect/src/app/teacher/store/teacher.effects.ts delete mode 100644 apps/ngrx/7-power-of-effect/src/app/teacher/store/teacher.reducer.ts delete mode 100644 apps/ngrx/7-power-of-effect/src/app/teacher/store/teacher.selectors.ts delete mode 100644 apps/ngrx/7-power-of-effect/src/app/teacher/teacher.component.ts delete mode 100644 apps/ngrx/7-power-of-effect/src/assets/.gitkeep delete mode 100644 apps/ngrx/7-power-of-effect/src/favicon.ico delete mode 100644 apps/ngrx/7-power-of-effect/src/index.html delete mode 100644 apps/ngrx/7-power-of-effect/src/main.ts delete mode 100644 apps/ngrx/7-power-of-effect/src/polyfills.ts delete mode 100644 apps/ngrx/7-power-of-effect/src/styles.scss delete mode 100644 apps/ngrx/7-power-of-effect/tsconfig.app.json delete mode 100644 apps/ngrx/7-power-of-effect/tsconfig.editor.json delete mode 100644 apps/ngrx/7-power-of-effect/tsconfig.json delete mode 100644 docs/src/content/docs/challenges/ngrx/2-effect-selector.md delete mode 100644 docs/src/content/docs/challenges/ngrx/7-power-effect.md delete mode 100644 libs/power-of-effect/backend/.eslintrc.json delete mode 100644 libs/power-of-effect/backend/README.md delete mode 100644 libs/power-of-effect/backend/jest.config.ts delete mode 100644 libs/power-of-effect/backend/project.json delete mode 100644 libs/power-of-effect/backend/src/index.ts delete mode 100644 libs/power-of-effect/backend/src/lib/fake-backend.service.ts delete mode 100644 libs/power-of-effect/backend/src/lib/fake-db.service.ts delete mode 100644 libs/power-of-effect/backend/src/lib/push.service.ts delete mode 100644 libs/power-of-effect/backend/src/test-setup.ts delete mode 100644 libs/power-of-effect/backend/tsconfig.json delete mode 100644 libs/power-of-effect/backend/tsconfig.lib.json delete mode 100644 libs/power-of-effect/backend/tsconfig.spec.json delete mode 100644 libs/power-of-effect/model/.eslintrc.json delete mode 100644 libs/power-of-effect/model/README.md delete mode 100644 libs/power-of-effect/model/jest.config.ts delete mode 100644 libs/power-of-effect/model/project.json delete mode 100644 libs/power-of-effect/model/src/index.ts delete mode 100644 libs/power-of-effect/model/src/lib/push.model.ts delete mode 100644 libs/power-of-effect/model/src/lib/school.model.ts delete mode 100644 libs/power-of-effect/model/src/lib/student.model.ts delete mode 100644 libs/power-of-effect/model/src/lib/teacher.model.ts delete mode 100644 libs/power-of-effect/model/src/test-setup.ts delete mode 100644 libs/power-of-effect/model/tsconfig.json delete mode 100644 libs/power-of-effect/model/tsconfig.lib.json delete mode 100644 libs/power-of-effect/model/tsconfig.spec.json delete mode 100644 libs/shared/ngrx-callstate-store/.eslintrc.json delete mode 100644 libs/shared/ngrx-callstate-store/README.md delete mode 100644 libs/shared/ngrx-callstate-store/jest.config.ts delete mode 100644 libs/shared/ngrx-callstate-store/ng-package.json delete mode 100644 libs/shared/ngrx-callstate-store/package.json delete mode 100644 libs/shared/ngrx-callstate-store/project.json delete mode 100644 libs/shared/ngrx-callstate-store/src/index.ts delete mode 100644 libs/shared/ngrx-callstate-store/src/lib/call-state-component-store.ts delete mode 100644 libs/shared/ngrx-callstate-store/src/lib/call-state.model.ts delete mode 100644 libs/shared/ngrx-callstate-store/src/lib/external.model.ts delete mode 100644 libs/shared/ngrx-callstate-store/src/lib/non-flicker-loader.ts delete mode 100644 libs/shared/ngrx-callstate-store/src/test-setup.ts delete mode 100644 libs/shared/ngrx-callstate-store/tsconfig.json delete mode 100644 libs/shared/ngrx-callstate-store/tsconfig.lib.json delete mode 100644 libs/shared/ngrx-callstate-store/tsconfig.lib.prod.json delete mode 100644 libs/shared/ngrx-callstate-store/tsconfig.spec.json diff --git a/apps/ngrx/2-effect-vs-selector/.eslintrc.json b/apps/ngrx/2-effect-vs-selector/.eslintrc.json deleted file mode 100644 index 8ebcbfd..0000000 --- a/apps/ngrx/2-effect-vs-selector/.eslintrc.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "extends": ["../../../.eslintrc.json"], - "ignorePatterns": ["!**/*"], - "overrides": [ - { - "files": ["*.ts"], - "extends": [ - "plugin:@nx/angular", - "plugin:@angular-eslint/template/process-inline-templates" - ], - "rules": { - "@angular-eslint/directive-selector": [ - "error", - { - "type": "attribute", - "prefix": "app", - "style": "camelCase" - } - ], - "@angular-eslint/component-selector": [ - "error", - { - "type": "element", - "prefix": "app", - "style": "kebab-case" - } - ] - } - }, - { - "files": ["*.html"], - "extends": ["plugin:@nx/angular-template"], - "rules": {} - } - ] -} diff --git a/apps/ngrx/2-effect-vs-selector/README.md b/apps/ngrx/2-effect-vs-selector/README.md deleted file mode 100644 index 4464073..0000000 --- a/apps/ngrx/2-effect-vs-selector/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Effect vs Selector - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve ngrx-effect-vs-selector -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/ngrx/2-effect-selector/). diff --git a/apps/ngrx/2-effect-vs-selector/jest.config.ts b/apps/ngrx/2-effect-vs-selector/jest.config.ts deleted file mode 100644 index 9581054..0000000 --- a/apps/ngrx/2-effect-vs-selector/jest.config.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'ngrx-effect-vs-selector', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/test-setup.ts'], - globals: {}, - coverageDirectory: '../../../coverage/apps/ngrx/2-effect-vs-selector', - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/apps/ngrx/2-effect-vs-selector/project.json b/apps/ngrx/2-effect-vs-selector/project.json deleted file mode 100644 index 13d5fd4..0000000 --- a/apps/ngrx/2-effect-vs-selector/project.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "name": "ngrx-effect-vs-selector", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/ngrx/2-effect-vs-selector/src", - "prefix": "app", - "tags": [], - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/ngrx/2-effect-vs-selector", - "index": "apps/ngrx/2-effect-vs-selector/src/index.html", - "main": "apps/ngrx/2-effect-vs-selector/src/main.ts", - "polyfills": "apps/ngrx/2-effect-vs-selector/src/polyfills.ts", - "tsConfig": "apps/ngrx/2-effect-vs-selector/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/ngrx/2-effect-vs-selector/src/favicon.ico", - "apps/ngrx/2-effect-vs-selector/src/assets" - ], - "styles": ["apps/ngrx/2-effect-vs-selector/src/styles.scss"], - "scripts": [], - "allowedCommonJsDependencies": ["seedrandom"] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "ngrx-effect-vs-selector:build:production" - }, - "development": { - "buildTarget": "ngrx-effect-vs-selector:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "ngrx-effect-vs-selector:build" - } - }, - "test": { - "options": { - "passWithNoTests": true - }, - "configurations": { - "ci": { - "ci": true, - "coverage": true - } - } - } - } -} diff --git a/apps/ngrx/2-effect-vs-selector/src/app/app.component.ts b/apps/ngrx/2-effect-vs-selector/src/app/app.component.ts deleted file mode 100644 index 640edbe..0000000 --- a/apps/ngrx/2-effect-vs-selector/src/app/app.component.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { AsyncPipe, NgFor } from '@angular/common'; -import { - ChangeDetectionStrategy, - Component, - OnInit, - inject, -} from '@angular/core'; -import { Store } from '@ngrx/store'; -import { loadActivities } from './store/activity/activity.actions'; -import { ActivityType } from './store/activity/activity.model'; -import { selectActivities } from './store/activity/activity.selectors'; -import { loadStatuses } from './store/status/status.actions'; -import { selectAllTeachersByActivityType } from './store/status/status.selectors'; -import { loadUsers } from './store/user/user.actions'; - -@Component({ - selector: 'app-root', - imports: [NgFor, AsyncPipe], - template: ` -

Activity Board

-
-
-

Activity Name: {{ activity.name }}

-

Main teacher: {{ activity.teacher.name }}

- All teachers available for : {{ activity.type }} are -
    -
  • - {{ teacher.name }} -
  • -
-
-
- `, - styles: [ - ` - section { - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 2px; - } - - .card { - display: flex; - flex-direction: column; - border: solid; - border-width: 1px; - border-color: black; - padding: 2px; - } - `, - ], - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class AppComponent implements OnInit { - private store = inject(Store); - - activities$ = this.store.select(selectActivities); - - ngOnInit(): void { - this.store.dispatch(loadActivities()); - this.store.dispatch(loadUsers()); - this.store.dispatch(loadStatuses()); - } - - getAllTeachersForActivityType$ = (type: ActivityType) => - this.store.select(selectAllTeachersByActivityType(type)); -} diff --git a/apps/ngrx/2-effect-vs-selector/src/app/app.config.ts b/apps/ngrx/2-effect-vs-selector/src/app/app.config.ts deleted file mode 100644 index d59c436..0000000 --- a/apps/ngrx/2-effect-vs-selector/src/app/app.config.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { ApplicationConfig } from '@angular/core'; -import { provideEffects } from '@ngrx/effects'; -import { provideStore } from '@ngrx/store'; -import { ActivityEffects } from './store/activity/activity.effects'; -import { - activityFeatureKey, - activityReducer, -} from './store/activity/activity.reducer'; -import { StatusEffects } from './store/status/status.effects'; -import { UserEffects } from './store/user/user.effects'; - -import { statusFeatureKey, statusReducer } from './store/status/status.reducer'; - -import { userFeatureKey, userReducer } from './store/user/user.reducer'; - -const reducers = { - [statusFeatureKey]: statusReducer, - [activityFeatureKey]: activityReducer, - [userFeatureKey]: userReducer, -}; - -export const appConfig: ApplicationConfig = { - providers: [ - provideStore(reducers), - provideEffects([ActivityEffects, UserEffects, StatusEffects]), - ], -}; diff --git a/apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.actions.ts b/apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.actions.ts deleted file mode 100644 index c8affff..0000000 --- a/apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.actions.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { createAction, props } from '@ngrx/store'; -import { Activity } from './activity.model'; - -export const loadActivities = createAction('[Activity Effect] Load Activities'); - -export const loadActivitiesSuccess = createAction( - '[Activity Effect] Load Activities Success', - props<{ activities: Activity[] }>(), -); - -export const loadActivitiesFailure = createAction( - '[Activity Effect] Load Activities Failure', - props<{ error: unknown }>(), -); diff --git a/apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.effects.ts b/apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.effects.ts deleted file mode 100644 index 88f8b23..0000000 --- a/apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.effects.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { of } from 'rxjs'; -import { catchError, concatMap, map } from 'rxjs/operators'; -import * as ActivityActions from './activity.actions'; -import { ActivityService } from './activity.service'; - -@Injectable() -export class ActivityEffects { - loadActivities$ = createEffect(() => { - return this.actions$.pipe( - ofType(ActivityActions.loadActivities), - concatMap(() => - this.ActivityService.fetchActivities().pipe( - map((activities) => - ActivityActions.loadActivitiesSuccess({ activities }), - ), - catchError((error) => - of(ActivityActions.loadActivitiesFailure({ error })), - ), - ), - ), - ); - }); - - constructor( - private actions$: Actions, - private ActivityService: ActivityService, - ) {} -} diff --git a/apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.model.ts b/apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.model.ts deleted file mode 100644 index 75f1881..0000000 --- a/apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.model.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { - incrementalNumber, - rand, - randFirstName, - randText, -} from '@ngneat/falso'; - -export const activityType = [ - 'Sport', - 'Sciences', - 'History', - 'Maths', - 'Physics', -] as const; -export type ActivityType = (typeof activityType)[number]; - -export interface Person { - id: number; - name: string; -} - -export interface Activity { - id: number; - name: string; - type: ActivityType; - teacher: Person; -} - -const factoryPerson = incrementalNumber(); - -export const randPerson = () => ({ - id: factoryPerson(), - name: randFirstName(), -}); - -const factoryActivity = incrementalNumber(); - -export const randActivity = (): Activity => ({ - id: factoryActivity(), - name: randText(), - type: rand(activityType), - teacher: randPerson(), -}); - -export const activities: Activity[] = [ - randActivity(), - randActivity(), - randActivity(), - randActivity(), - randActivity(), - randActivity(), - randActivity(), - randActivity(), - randActivity(), -]; diff --git a/apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.reducer.ts b/apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.reducer.ts deleted file mode 100644 index b7285e8..0000000 --- a/apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.reducer.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { createReducer, on } from '@ngrx/store'; -import * as ActivityActions from './activity.actions'; -import { Activity } from './activity.model'; - -export const activityFeatureKey = 'Activity'; - -export interface ActivityState { - activities: Activity[]; -} - -export const initialState: ActivityState = { - activities: [], -}; - -export const activityReducer = createReducer( - initialState, - on(ActivityActions.loadActivitiesSuccess, (state, { activities }) => ({ - ...state, - activities, - })), - on(ActivityActions.loadActivitiesFailure, (state) => ({ - state, - activities: [], - })), -); diff --git a/apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.selectors.ts b/apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.selectors.ts deleted file mode 100644 index 6c6a25a..0000000 --- a/apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.selectors.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { createFeatureSelector, createSelector } from '@ngrx/store'; -import { ActivityState, activityFeatureKey } from './activity.reducer'; - -export const selectActivityState = - createFeatureSelector(activityFeatureKey); - -export const selectActivities = createSelector( - selectActivityState, - (state) => state.activities, -); diff --git a/apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.service.ts b/apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.service.ts deleted file mode 100644 index 07aa8f8..0000000 --- a/apps/ngrx/2-effect-vs-selector/src/app/store/activity/activity.service.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Injectable } from '@angular/core'; -import { map, timer } from 'rxjs'; -import { activities } from './activity.model'; - -@Injectable({ - providedIn: 'root', -}) -export class ActivityService { - fetchActivities = () => timer(500).pipe(map(() => activities)); -} diff --git a/apps/ngrx/2-effect-vs-selector/src/app/store/status/status.actions.ts b/apps/ngrx/2-effect-vs-selector/src/app/store/status/status.actions.ts deleted file mode 100644 index 8fc2ddc..0000000 --- a/apps/ngrx/2-effect-vs-selector/src/app/store/status/status.actions.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { createAction, props } from '@ngrx/store'; -import { Status } from './status.model'; - -export const loadStatuses = createAction('[Status] Load Statuses'); - -export const loadStatusesSuccess = createAction( - '[Status] Load Statuses Success', - props<{ statuses: Status[] }>(), -); diff --git a/apps/ngrx/2-effect-vs-selector/src/app/store/status/status.effects.ts b/apps/ngrx/2-effect-vs-selector/src/app/store/status/status.effects.ts deleted file mode 100644 index 997eb0c..0000000 --- a/apps/ngrx/2-effect-vs-selector/src/app/store/status/status.effects.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { Store } from '@ngrx/store'; -import { combineLatest, concatMap, map } from 'rxjs'; -import { selectActivities } from '../activity/activity.selectors'; -import { selectUser } from '../user/user.selectors'; -import * as StatusActions from './status.actions'; -import { Status } from './status.model'; - -@Injectable() -export class StatusEffects { - loadStatuses$ = createEffect(() => { - return this.actions$.pipe( - ofType(StatusActions.loadStatuses), - concatMap(() => - combineLatest([ - this.store.select(selectUser), - this.store.select(selectActivities), - ]).pipe( - map(([user, activities]): Status[] => { - if (user?.isAdmin) { - return activities.reduce( - (status: Status[], activity): Status[] => { - const index = status.findIndex( - (s) => s.name === activity.type, - ); - if (index === -1) { - return [ - ...status, - { name: activity.type, teachers: [activity.teacher] }, - ]; - } else { - status[index].teachers.push(activity.teacher); - return status; - } - }, - [], - ); - } - return []; - }), - map((statuses) => StatusActions.loadStatusesSuccess({ statuses })), - ), - ), - ); - }); - - constructor( - private actions$: Actions, - private store: Store, - ) {} -} diff --git a/apps/ngrx/2-effect-vs-selector/src/app/store/status/status.model.ts b/apps/ngrx/2-effect-vs-selector/src/app/store/status/status.model.ts deleted file mode 100644 index 0773383..0000000 --- a/apps/ngrx/2-effect-vs-selector/src/app/store/status/status.model.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { ActivityType, Person } from '../activity/activity.model'; - -export interface Status { - name: ActivityType; - teachers: Person[]; -} diff --git a/apps/ngrx/2-effect-vs-selector/src/app/store/status/status.reducer.ts b/apps/ngrx/2-effect-vs-selector/src/app/store/status/status.reducer.ts deleted file mode 100644 index b91cbe2..0000000 --- a/apps/ngrx/2-effect-vs-selector/src/app/store/status/status.reducer.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { createReducer, on } from '@ngrx/store'; -import { ActivityType, Person } from '../activity/activity.model'; -import * as StatusActions from './status.actions'; -import { Status } from './status.model'; - -export const statusFeatureKey = 'status'; - -export interface StatusState { - statuses: Status[]; - teachersMap: Map; -} - -export const initialState: StatusState = { - statuses: [], - teachersMap: new Map(), -}; - -export const statusReducer = createReducer( - initialState, - on(StatusActions.loadStatusesSuccess, (state, { statuses }): StatusState => { - const map = new Map(); - statuses.forEach((s) => map.set(s.name, s.teachers)); - return { - ...state, - statuses, - teachersMap: map, - }; - }), -); diff --git a/apps/ngrx/2-effect-vs-selector/src/app/store/status/status.selectors.ts b/apps/ngrx/2-effect-vs-selector/src/app/store/status/status.selectors.ts deleted file mode 100644 index 80ed059..0000000 --- a/apps/ngrx/2-effect-vs-selector/src/app/store/status/status.selectors.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { createFeatureSelector, createSelector } from '@ngrx/store'; -import { ActivityType } from '../activity/activity.model'; -import { StatusState, statusFeatureKey } from './status.reducer'; - -export const selectStatusState = - createFeatureSelector(statusFeatureKey); - -export const selectStatuses = createSelector( - selectStatusState, - (state) => state.statuses, -); - -export const selectAllTeachersByActivityType = (name: ActivityType) => - createSelector( - selectStatusState, - (state) => state.teachersMap.get(name) ?? [], - ); diff --git a/apps/ngrx/2-effect-vs-selector/src/app/store/user/user.actions.ts b/apps/ngrx/2-effect-vs-selector/src/app/store/user/user.actions.ts deleted file mode 100644 index a73147d..0000000 --- a/apps/ngrx/2-effect-vs-selector/src/app/store/user/user.actions.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { createAction, props } from '@ngrx/store'; -import { User } from './user.model'; - -export const loadUsers = createAction('[User] Load Users'); - -export const loadUsersSuccess = createAction( - '[User] Load Users Success', - props<{ user: User }>(), -); - -export const loadUsersFailure = createAction( - '[User] Load Users Failure', - props<{ error: unknown }>(), -); diff --git a/apps/ngrx/2-effect-vs-selector/src/app/store/user/user.effects.ts b/apps/ngrx/2-effect-vs-selector/src/app/store/user/user.effects.ts deleted file mode 100644 index fff3f6f..0000000 --- a/apps/ngrx/2-effect-vs-selector/src/app/store/user/user.effects.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { of } from 'rxjs'; -import { catchError, concatMap, map } from 'rxjs/operators'; -import * as UserActions from './user.actions'; -import { UserService } from './user.service'; - -@Injectable() -export class UserEffects { - loadUsers$ = createEffect(() => { - return this.actions$.pipe( - ofType(UserActions.loadUsers), - concatMap(() => - this.userService.fetchUser().pipe( - map((user) => UserActions.loadUsersSuccess({ user })), - catchError((error) => of(UserActions.loadUsersFailure({ error }))), - ), - ), - ); - }); - - constructor( - private actions$: Actions, - private userService: UserService, - ) {} -} diff --git a/apps/ngrx/2-effect-vs-selector/src/app/store/user/user.model.ts b/apps/ngrx/2-effect-vs-selector/src/app/store/user/user.model.ts deleted file mode 100644 index d769204..0000000 --- a/apps/ngrx/2-effect-vs-selector/src/app/store/user/user.model.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { randFirstName, randLastName, randText } from '@ngneat/falso'; - -export interface User { - firstname: string; - lastname: string; - isAdmin: boolean; - apiKey: string; -} - -export const user: User = { - firstname: randFirstName(), - lastname: randLastName(), - isAdmin: true, - apiKey: randText(), -}; diff --git a/apps/ngrx/2-effect-vs-selector/src/app/store/user/user.reducer.ts b/apps/ngrx/2-effect-vs-selector/src/app/store/user/user.reducer.ts deleted file mode 100644 index 3f4768c..0000000 --- a/apps/ngrx/2-effect-vs-selector/src/app/store/user/user.reducer.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { createReducer, on } from '@ngrx/store'; -import * as UserActions from './user.actions'; -import { User } from './user.model'; - -export const userFeatureKey = 'user'; - -export interface UserState { - user?: User; -} - -export const initialState: UserState = { - user: undefined, -}; - -export const userReducer = createReducer( - initialState, - on(UserActions.loadUsersSuccess, (state, { user }) => ({ ...state, user })), - on(UserActions.loadUsersFailure, (state) => ({ ...state, user: undefined })), -); diff --git a/apps/ngrx/2-effect-vs-selector/src/app/store/user/user.selectors.ts b/apps/ngrx/2-effect-vs-selector/src/app/store/user/user.selectors.ts deleted file mode 100644 index 7970b0d..0000000 --- a/apps/ngrx/2-effect-vs-selector/src/app/store/user/user.selectors.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { createFeatureSelector, createSelector } from '@ngrx/store'; -import { UserState, userFeatureKey } from './user.reducer'; - -export const selectUserState = createFeatureSelector(userFeatureKey); - -export const selectUser = createSelector( - selectUserState, - (state) => state.user, -); diff --git a/apps/ngrx/2-effect-vs-selector/src/app/store/user/user.service.ts b/apps/ngrx/2-effect-vs-selector/src/app/store/user/user.service.ts deleted file mode 100644 index a407b02..0000000 --- a/apps/ngrx/2-effect-vs-selector/src/app/store/user/user.service.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Injectable } from '@angular/core'; -import { map, timer } from 'rxjs'; -import { user } from './user.model'; - -@Injectable({ - providedIn: 'root', -}) -export class UserService { - fetchUser = () => timer(500).pipe(map(() => user)); -} diff --git a/apps/ngrx/2-effect-vs-selector/src/assets/.gitkeep b/apps/ngrx/2-effect-vs-selector/src/assets/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/apps/ngrx/2-effect-vs-selector/src/favicon.ico b/apps/ngrx/2-effect-vs-selector/src/favicon.ico deleted file mode 100644 index 317ebcb2336e0833a22dddf0ab287849f26fda57..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15086 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 - - - - ngrx-effect-vs-selector - - - - - - - - diff --git a/apps/ngrx/2-effect-vs-selector/src/main.ts b/apps/ngrx/2-effect-vs-selector/src/main.ts deleted file mode 100644 index 31c2a34..0000000 --- a/apps/ngrx/2-effect-vs-selector/src/main.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { bootstrapApplication } from '@angular/platform-browser'; -import { appConfig } from './app/app.config'; - -import { AppComponent } from './app/app.component'; - -bootstrapApplication(AppComponent, appConfig); diff --git a/apps/ngrx/2-effect-vs-selector/src/polyfills.ts b/apps/ngrx/2-effect-vs-selector/src/polyfills.ts deleted file mode 100644 index e4555ed..0000000 --- a/apps/ngrx/2-effect-vs-selector/src/polyfills.ts +++ /dev/null @@ -1,52 +0,0 @@ -/** - * This file includes polyfills needed by Angular and is loaded before the app. - * You can add your own extra polyfills to this file. - * - * This file is divided into 2 sections: - * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. - * 2. Application imports. Files imported after ZoneJS that should be loaded before your main - * file. - * - * The current setup is for so-called "evergreen" browsers; the last versions of browsers that - * automatically update themselves. This includes recent versions of Safari, Chrome (including - * Opera), Edge on the desktop, and iOS and Chrome on mobile. - * - * Learn more in https://angular.io/guide/browser-support - */ - -/*************************************************************************************************** - * BROWSER POLYFILLS - */ - -/** - * By default, zone.js will patch all possible macroTask and DomEvents - * user can disable parts of macroTask/DomEvents patch by setting following flags - * because those flags need to be set before `zone.js` being loaded, and webpack - * will put import in the top of bundle, so user need to create a separate file - * in this directory (for example: zone-flags.ts), and put the following flags - * into that file, and then add the following code before importing zone.js. - * import './zone-flags'; - * - * The flags allowed in zone-flags.ts are listed here. - * - * The following flags will work for all browsers. - * - * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame - * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick - * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames - * - * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js - * with the following flag, it will bypass `zone.js` patch for IE/Edge - * - * (window as any).__Zone_enable_cross_context_check = true; - * - */ - -/*************************************************************************************************** - * Zone JS is required by default for Angular itself. - */ -import 'zone.js'; // Included with Angular CLI. - -/*************************************************************************************************** - * APPLICATION IMPORTS - */ diff --git a/apps/ngrx/2-effect-vs-selector/src/styles.scss b/apps/ngrx/2-effect-vs-selector/src/styles.scss deleted file mode 100644 index e69de29..0000000 diff --git a/apps/ngrx/2-effect-vs-selector/src/test-setup.ts b/apps/ngrx/2-effect-vs-selector/src/test-setup.ts deleted file mode 100644 index 1100b3e..0000000 --- a/apps/ngrx/2-effect-vs-selector/src/test-setup.ts +++ /dev/null @@ -1 +0,0 @@ -import 'jest-preset-angular/setup-jest'; diff --git a/apps/ngrx/2-effect-vs-selector/tsconfig.app.json b/apps/ngrx/2-effect-vs-selector/tsconfig.app.json deleted file mode 100644 index 7a4dbc4..0000000 --- a/apps/ngrx/2-effect-vs-selector/tsconfig.app.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../dist/out-tsc", - "types": [], - "target": "ES2022", - "useDefineForClassFields": false - }, - "files": ["src/main.ts", "src/polyfills.ts"], - "include": ["src/**/*.d.ts"], - "exclude": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts"] -} diff --git a/apps/ngrx/2-effect-vs-selector/tsconfig.editor.json b/apps/ngrx/2-effect-vs-selector/tsconfig.editor.json deleted file mode 100644 index 20c4afd..0000000 --- a/apps/ngrx/2-effect-vs-selector/tsconfig.editor.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "./tsconfig.json", - "include": ["**/*.ts"], - "compilerOptions": { - "types": ["jest", "node"] - } -} diff --git a/apps/ngrx/2-effect-vs-selector/tsconfig.json b/apps/ngrx/2-effect-vs-selector/tsconfig.json deleted file mode 100644 index 52eb4f7..0000000 --- a/apps/ngrx/2-effect-vs-selector/tsconfig.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.app.json" - }, - { - "path": "./tsconfig.spec.json" - }, - { - "path": "./tsconfig.editor.json" - } - ], - "compilerOptions": { - "target": "es2020", - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true - }, - "angularCompilerOptions": { - "enableI18nLegacyMessageIdFormat": false, - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true - } -} diff --git a/apps/ngrx/2-effect-vs-selector/tsconfig.spec.json b/apps/ngrx/2-effect-vs-selector/tsconfig.spec.json deleted file mode 100644 index 7aa46d8..0000000 --- a/apps/ngrx/2-effect-vs-selector/tsconfig.spec.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../dist/out-tsc", - "module": "commonjs", - "types": ["jest", "node"] - }, - "files": ["src/test-setup.ts"], - "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] -} diff --git a/apps/ngrx/7-power-of-effect/.eslintrc.json b/apps/ngrx/7-power-of-effect/.eslintrc.json deleted file mode 100644 index 8ebcbfd..0000000 --- a/apps/ngrx/7-power-of-effect/.eslintrc.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "extends": ["../../../.eslintrc.json"], - "ignorePatterns": ["!**/*"], - "overrides": [ - { - "files": ["*.ts"], - "extends": [ - "plugin:@nx/angular", - "plugin:@angular-eslint/template/process-inline-templates" - ], - "rules": { - "@angular-eslint/directive-selector": [ - "error", - { - "type": "attribute", - "prefix": "app", - "style": "camelCase" - } - ], - "@angular-eslint/component-selector": [ - "error", - { - "type": "element", - "prefix": "app", - "style": "kebab-case" - } - ] - } - }, - { - "files": ["*.html"], - "extends": ["plugin:@nx/angular-template"], - "rules": {} - } - ] -} diff --git a/apps/ngrx/7-power-of-effect/README.md b/apps/ngrx/7-power-of-effect/README.md deleted file mode 100644 index b185004..0000000 --- a/apps/ngrx/7-power-of-effect/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Power of Effect - -> author: thomas-laforge - -### Run Application - -```bash -npx nx serve ngrx-power-of-effect -``` - -### Documentation and Instruction - -Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/ngrx/7-power-effect/). diff --git a/apps/ngrx/7-power-of-effect/project.json b/apps/ngrx/7-power-of-effect/project.json deleted file mode 100644 index f52c058..0000000 --- a/apps/ngrx/7-power-of-effect/project.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "name": "ngrx-power-of-effect", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/ngrx/7-power-of-effect/src", - "prefix": "app", - "tags": [], - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/ngrx/7-power-of-effect", - "index": "apps/ngrx/7-power-of-effect/src/index.html", - "main": "apps/ngrx/7-power-of-effect/src/main.ts", - "polyfills": "apps/ngrx/7-power-of-effect/src/polyfills.ts", - "tsConfig": "apps/ngrx/7-power-of-effect/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": [ - "apps/ngrx/7-power-of-effect/src/favicon.ico", - "apps/ngrx/7-power-of-effect/src/assets" - ], - "styles": [ - "apps/ngrx/7-power-of-effect/src/styles.scss", - "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css" - ], - "scripts": [], - "allowedCommonJsDependencies": ["seedrandom"] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all" - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "ngrx-power-of-effect:build:production" - }, - "development": { - "buildTarget": "ngrx-power-of-effect:build:development" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "buildTarget": "ngrx-power-of-effect:build" - } - } - } -} diff --git a/apps/ngrx/7-power-of-effect/src/app/app.actions.ts b/apps/ngrx/7-power-of-effect/src/app/app.actions.ts deleted file mode 100644 index 3dcba81..0000000 --- a/apps/ngrx/7-power-of-effect/src/app/app.actions.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { createActionGroup, emptyProps } from '@ngrx/store'; - -// This is the global actions. -export const appActions = createActionGroup({ - source: 'App Component', - events: { - 'Init App': emptyProps(), - }, -}); diff --git a/apps/ngrx/7-power-of-effect/src/app/app.component.ts b/apps/ngrx/7-power-of-effect/src/app/app.component.ts deleted file mode 100644 index ec4b8cd..0000000 --- a/apps/ngrx/7-power-of-effect/src/app/app.component.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Component, inject, OnInit } from '@angular/core'; -import { RouterLink, RouterOutlet } from '@angular/router'; -import { Store } from '@ngrx/store'; -import { appActions } from './app.actions'; - -@Component({ - imports: [RouterOutlet, RouterLink], - selector: 'app-root', - template: ` - - - - `, - styles: [ - ` - :host { - display: flex; - flex-direction: column; - gap: 20px; - - nav { - display: flex; - gap: 20px; - } - } - `, - ], -}) -export class AppComponent implements OnInit { - private store = inject(Store); - - ngOnInit(): void { - this.store.dispatch(appActions.initApp()); - } -} diff --git a/apps/ngrx/7-power-of-effect/src/app/app.config.ts b/apps/ngrx/7-power-of-effect/src/app/app.config.ts deleted file mode 100644 index 640f324..0000000 --- a/apps/ngrx/7-power-of-effect/src/app/app.config.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { FakeBackendService } from '@angular-challenges/power-of-effect/backend'; -import { - ApplicationConfig, - inject, - provideAppInitializer, -} from '@angular/core'; -import { provideAnimations } from '@angular/platform-browser/animations'; -import { provideRouter } from '@angular/router'; -import { provideEffects } from '@ngrx/effects'; -import { provideStore } from '@ngrx/store'; -import { NotificationService } from './data-access/notification.service'; -import { ROUTES } from './routes'; -import { StudentEffects } from './student/store/student.effects'; -import { - studentReducer, - studentsFeatureKey, -} from './student/store/student.reducer'; -import { TeacherEffects } from './teacher/store/teacher.effects'; -import { - teacherReducer, - teachersFeatureKey, -} from './teacher/store/teacher.reducer'; - -const REDUCERS = { - [teachersFeatureKey]: teacherReducer, - [studentsFeatureKey]: studentReducer, -}; - -export const appConfig: ApplicationConfig = { - providers: [ - provideStore(REDUCERS), - provideEffects([TeacherEffects, StudentEffects]), - provideRouter(ROUTES), - provideAppInitializer(() => { - const initializerFn = (() => { - const service = inject(FakeBackendService); - return () => service.start(); - })(); - return initializerFn(); - }), - provideAppInitializer(() => { - const initializerFn = (() => { - const service = inject(NotificationService); - return () => service.init(); - })(); - return initializerFn(); - }), - provideAnimations(), - ], -}; diff --git a/apps/ngrx/7-power-of-effect/src/app/data-access/http.service.ts b/apps/ngrx/7-power-of-effect/src/app/data-access/http.service.ts deleted file mode 100644 index b5494b5..0000000 --- a/apps/ngrx/7-power-of-effect/src/app/data-access/http.service.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { FakeBackendService } from '@angular-challenges/power-of-effect/backend'; -import { inject, Injectable } from '@angular/core'; -import { take } from 'rxjs'; - -@Injectable({ providedIn: 'root' }) -export class HttpService { - private fakeBackend = inject(FakeBackendService); - - getAllTeachers = () => this.fakeBackend.getAllTeachers().pipe(take(1)); - - getAllStudents = () => this.fakeBackend.getAllStudents().pipe(take(1)); - - getAllSchools = () => this.fakeBackend.getAllSchools().pipe(take(1)); -} diff --git a/apps/ngrx/7-power-of-effect/src/app/data-access/notification.service.ts b/apps/ngrx/7-power-of-effect/src/app/data-access/notification.service.ts deleted file mode 100644 index 5d9ed38..0000000 --- a/apps/ngrx/7-power-of-effect/src/app/data-access/notification.service.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { PushService } from '@angular-challenges/power-of-effect/backend'; -import { - isSchool, - isStudent, - isTeacher, - Push, -} from '@angular-challenges/power-of-effect/model'; -import { inject, Injectable } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { filter } from 'rxjs'; -import { studentActions } from '../student/store/student.actions'; -import { teacherActions } from '../teacher/store/teacher.actions'; - -@Injectable({ providedIn: 'root' }) -export class NotificationService { - private pushService = inject(PushService); - private store = inject(Store); - - init() { - this.pushService.notification$ - .pipe(filter(Boolean)) - .subscribe((notification: Push) => { - if (isTeacher(notification)) { - this.store.dispatch( - teacherActions.addOneTeacher({ teacher: notification }), - ); - } - if (isStudent(notification)) { - this.store.dispatch( - studentActions.addOneStudent({ student: notification }), - ); - } - if (isSchool(notification)) { - // SchoolStore is a ComponentStore. We can't dispatch a school action here. - // We are stuck. We must have done something wrong and need to refactor... - } - }); - } -} diff --git a/apps/ngrx/7-power-of-effect/src/app/routes.ts b/apps/ngrx/7-power-of-effect/src/app/routes.ts deleted file mode 100644 index 7db44a4..0000000 --- a/apps/ngrx/7-power-of-effect/src/app/routes.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Route } from '@angular/router'; -import { TeacherComponent } from './teacher/teacher.component'; - -export const ROUTES: Route[] = [ - { path: '', pathMatch: 'full', redirectTo: 'teacher' }, - { - path: 'teacher', - component: TeacherComponent, - }, - { - path: 'student', - loadComponent: () => - import('./student/student.component').then((m) => m.StudentComponent), - }, - { - path: 'school', - loadComponent: () => - import('./school/school.component').then((m) => m.SchoolComponent), - }, -]; diff --git a/apps/ngrx/7-power-of-effect/src/app/school/school.component.ts b/apps/ngrx/7-power-of-effect/src/app/school/school.component.ts deleted file mode 100644 index 999cdc6..0000000 --- a/apps/ngrx/7-power-of-effect/src/app/school/school.component.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* eslint-disable @angular-eslint/component-selector */ -import { AsyncPipe, NgFor } from '@angular/common'; -import { Component, inject } from '@angular/core'; -import { provideComponentStore } from '@ngrx/component-store'; -import { SchoolStore } from './school.store'; - -@Component({ - imports: [NgFor, AsyncPipe], - providers: [provideComponentStore(SchoolStore)], - selector: 'school', - template: ` -

SCHOOL

-
- {{ school.name }} - {{ school.version }} -
- `, - styles: [ - ` - :host { - display: block; - width: fit-content; - height: fit-content; - border: 1px solid red; - padding: 4px; - } - `, - ], -}) -export class SchoolComponent { - private store = inject(SchoolStore); - school$ = this.store.schools$; -} diff --git a/apps/ngrx/7-power-of-effect/src/app/school/school.store.ts b/apps/ngrx/7-power-of-effect/src/app/school/school.store.ts deleted file mode 100644 index c24267f..0000000 --- a/apps/ngrx/7-power-of-effect/src/app/school/school.store.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { School } from '@angular-challenges/power-of-effect/model'; -import { Injectable } from '@angular/core'; -import { ComponentStore, OnStoreInit } from '@ngrx/component-store'; -import { tapResponse } from '@ngrx/operators'; -import { pipe, switchMap } from 'rxjs'; -import { HttpService } from '../data-access/http.service'; - -@Injectable() -export class SchoolStore - extends ComponentStore<{ schools: School[] }> - implements OnStoreInit -{ - readonly schools$ = this.select((state) => state.schools); - - constructor(private httpService: HttpService) { - super({ schools: [] }); - } - - addSchool = this.updater((state, school: School) => ({ - ...state, - schools: [...state.schools, school], - })); - - updateSchool = this.updater((state, school: School) => ({ - ...state, - schools: state.schools.map((t) => (t.id === school.id ? school : t)), - })); - - private readonly loadSchools = this.effect( - pipe( - switchMap(() => - this.httpService.getAllSchools().pipe( - tapResponse( - (schools) => this.patchState({ schools }), - (_) => _, // not handling the error - ), - ), - ), - ), - ); - - ngrxOnStoreInit() { - this.loadSchools(); - } -} diff --git a/apps/ngrx/7-power-of-effect/src/app/student/store/student.actions.ts b/apps/ngrx/7-power-of-effect/src/app/student/store/student.actions.ts deleted file mode 100644 index 3d877a1..0000000 --- a/apps/ngrx/7-power-of-effect/src/app/student/store/student.actions.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Student } from '@angular-challenges/power-of-effect/model'; -import { createActionGroup, props } from '@ngrx/store'; - -export const studentActions = createActionGroup({ - source: 'Student API', - events: { - 'Add One Student': props<{ student: Student }>(), - 'Add All Students': props<{ students: Student[] }>(), - }, -}); diff --git a/apps/ngrx/7-power-of-effect/src/app/student/store/student.effects.ts b/apps/ngrx/7-power-of-effect/src/app/student/store/student.effects.ts deleted file mode 100644 index b741bd2..0000000 --- a/apps/ngrx/7-power-of-effect/src/app/student/store/student.effects.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { inject, Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { map, switchMap } from 'rxjs'; -import { appActions } from '../../app.actions'; -import { HttpService } from '../../data-access/http.service'; -import { studentActions } from './student.actions'; - -@Injectable() -export class StudentEffects { - private actions$ = inject(Actions); - private httpService = inject(HttpService); - - loadStudents$ = createEffect(() => - this.actions$.pipe( - ofType(appActions.initApp), - switchMap(() => - this.httpService - .getAllStudents() - .pipe(map((students) => studentActions.addAllStudents({ students }))), - ), - ), - ); -} diff --git a/apps/ngrx/7-power-of-effect/src/app/student/store/student.reducer.ts b/apps/ngrx/7-power-of-effect/src/app/student/store/student.reducer.ts deleted file mode 100644 index 56fe09a..0000000 --- a/apps/ngrx/7-power-of-effect/src/app/student/store/student.reducer.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Student } from '@angular-challenges/power-of-effect/model'; -import { createEntityAdapter, EntityAdapter, EntityState } from '@ngrx/entity'; -import { createReducer, on } from '@ngrx/store'; -import { studentActions } from './student.actions'; - -export const studentsFeatureKey = 'students'; - -export type StudentState = EntityState; - -export const studentAdapter: EntityAdapter = - createEntityAdapter(); - -export const studentReducer = createReducer( - studentAdapter.getInitialState(), - on(studentActions.addOneStudent, (state, { student }) => - studentAdapter.upsertOne(student, state), - ), - on(studentActions.addAllStudents, (state, { students }) => - studentAdapter.setAll(students, state), - ), -); - -export const { selectIds, selectEntities, selectAll, selectTotal } = - studentAdapter.getSelectors(); diff --git a/apps/ngrx/7-power-of-effect/src/app/student/store/student.selectors.ts b/apps/ngrx/7-power-of-effect/src/app/student/store/student.selectors.ts deleted file mode 100644 index b041ff4..0000000 --- a/apps/ngrx/7-power-of-effect/src/app/student/store/student.selectors.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { createFeatureSelector, createSelector } from '@ngrx/store'; -import { - StudentState, - studentAdapter, - studentsFeatureKey, -} from './student.reducer'; - -const selectStudentState = - createFeatureSelector(studentsFeatureKey); - -export const { selectAll } = studentAdapter.getSelectors(); - -const selectStudents = createSelector(selectStudentState, selectAll); - -export const StudentSelectors = { - selectStudents, -}; diff --git a/apps/ngrx/7-power-of-effect/src/app/student/student.component.ts b/apps/ngrx/7-power-of-effect/src/app/student/student.component.ts deleted file mode 100644 index 95447ea..0000000 --- a/apps/ngrx/7-power-of-effect/src/app/student/student.component.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* eslint-disable @angular-eslint/component-selector */ -import { AsyncPipe, NgFor } from '@angular/common'; -import { Component, inject } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { StudentSelectors } from './store/student.selectors'; - -@Component({ - imports: [NgFor, AsyncPipe], - selector: 'student', - template: ` -

STUDENTS

-
- {{ student.firstname }} {{ student.lastname }} - {{ student.version }} -
- `, - styles: [ - ` - :host { - display: block; - width: fit-content; - height: fit-content; - border: 1px solid red; - padding: 4px; - } - `, - ], -}) -export class StudentComponent { - private store = inject(Store); - students$ = this.store.select(StudentSelectors.selectStudents); -} diff --git a/apps/ngrx/7-power-of-effect/src/app/teacher/store/teacher.actions.ts b/apps/ngrx/7-power-of-effect/src/app/teacher/store/teacher.actions.ts deleted file mode 100644 index 21bae01..0000000 --- a/apps/ngrx/7-power-of-effect/src/app/teacher/store/teacher.actions.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Teacher } from '@angular-challenges/power-of-effect/model'; -import { createActionGroup, props } from '@ngrx/store'; - -export const teacherActions = createActionGroup({ - source: 'Teacher API', - events: { - 'Add One Teacher': props<{ teacher: Teacher }>(), - 'Add All Teachers': props<{ teachers: Teacher[] }>(), - }, -}); diff --git a/apps/ngrx/7-power-of-effect/src/app/teacher/store/teacher.effects.ts b/apps/ngrx/7-power-of-effect/src/app/teacher/store/teacher.effects.ts deleted file mode 100644 index 43c3fab..0000000 --- a/apps/ngrx/7-power-of-effect/src/app/teacher/store/teacher.effects.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { inject, Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { map, switchMap } from 'rxjs'; -import { appActions } from '../../app.actions'; -import { HttpService } from '../../data-access/http.service'; -import { teacherActions } from './teacher.actions'; - -@Injectable() -export class TeacherEffects { - private actions$ = inject(Actions); - private httpService = inject(HttpService); - - loadTeachers$ = createEffect(() => - this.actions$.pipe( - ofType(appActions.initApp), - switchMap(() => - this.httpService - .getAllTeachers() - .pipe(map((teachers) => teacherActions.addAllTeachers({ teachers }))), - ), - ), - ); -} diff --git a/apps/ngrx/7-power-of-effect/src/app/teacher/store/teacher.reducer.ts b/apps/ngrx/7-power-of-effect/src/app/teacher/store/teacher.reducer.ts deleted file mode 100644 index 7174fba..0000000 --- a/apps/ngrx/7-power-of-effect/src/app/teacher/store/teacher.reducer.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Teacher } from '@angular-challenges/power-of-effect/model'; -import { createEntityAdapter, EntityAdapter, EntityState } from '@ngrx/entity'; -import { createReducer, on } from '@ngrx/store'; -import { teacherActions } from './teacher.actions'; - -export const teachersFeatureKey = 'teachers'; - -export type TeacherState = EntityState; - -export const teacherAdapter: EntityAdapter = - createEntityAdapter(); - -export const teacherReducer = createReducer( - teacherAdapter.getInitialState(), - on(teacherActions.addOneTeacher, (state, { teacher }) => - teacherAdapter.upsertOne(teacher, state), - ), - on(teacherActions.addAllTeachers, (state, { teachers }) => - teacherAdapter.setAll(teachers, state), - ), -); - -export const { selectIds, selectEntities, selectAll, selectTotal } = - teacherAdapter.getSelectors(); diff --git a/apps/ngrx/7-power-of-effect/src/app/teacher/store/teacher.selectors.ts b/apps/ngrx/7-power-of-effect/src/app/teacher/store/teacher.selectors.ts deleted file mode 100644 index a32e82c..0000000 --- a/apps/ngrx/7-power-of-effect/src/app/teacher/store/teacher.selectors.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { createFeatureSelector, createSelector } from '@ngrx/store'; -import { - TeacherState, - teacherAdapter, - teachersFeatureKey, -} from './teacher.reducer'; - -const selectTeacherState = - createFeatureSelector(teachersFeatureKey); - -export const { selectAll } = teacherAdapter.getSelectors(); - -const selectTeachers = createSelector(selectTeacherState, selectAll); - -export const TeacherSelectors = { - selectTeachers, -}; diff --git a/apps/ngrx/7-power-of-effect/src/app/teacher/teacher.component.ts b/apps/ngrx/7-power-of-effect/src/app/teacher/teacher.component.ts deleted file mode 100644 index d41a7c9..0000000 --- a/apps/ngrx/7-power-of-effect/src/app/teacher/teacher.component.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* eslint-disable @angular-eslint/component-selector */ -import { AsyncPipe, NgFor } from '@angular/common'; -import { Component } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { TeacherSelectors } from './store/teacher.selectors'; - -@Component({ - imports: [NgFor, AsyncPipe], - selector: 'teacher', - template: ` -

TEACHERS

-
- {{ teacher.firstname }} {{ teacher.lastname }} - {{ teacher.version }} -
- `, - styles: [ - ` - :host { - display: block; - width: fit-content; - height: fit-content; - border: 1px solid red; - padding: 4px; - } - `, - ], -}) -export class TeacherComponent { - teacher$ = this.store.select(TeacherSelectors.selectTeachers); - - constructor(private store: Store) {} -} diff --git a/apps/ngrx/7-power-of-effect/src/assets/.gitkeep b/apps/ngrx/7-power-of-effect/src/assets/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/apps/ngrx/7-power-of-effect/src/favicon.ico b/apps/ngrx/7-power-of-effect/src/favicon.ico deleted file mode 100644 index 317ebcb2336e0833a22dddf0ab287849f26fda57..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15086 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 - - - - ngrx-power-of-effect - - - - - - - - diff --git a/apps/ngrx/7-power-of-effect/src/main.ts b/apps/ngrx/7-power-of-effect/src/main.ts deleted file mode 100644 index 6f91f21..0000000 --- a/apps/ngrx/7-power-of-effect/src/main.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { appConfig } from './app/app.config'; - -import { bootstrapApplication } from '@angular/platform-browser'; - -import { AppComponent } from './app/app.component'; - -bootstrapApplication(AppComponent, appConfig).catch((err) => - console.error(err), -); diff --git a/apps/ngrx/7-power-of-effect/src/polyfills.ts b/apps/ngrx/7-power-of-effect/src/polyfills.ts deleted file mode 100644 index e4555ed..0000000 --- a/apps/ngrx/7-power-of-effect/src/polyfills.ts +++ /dev/null @@ -1,52 +0,0 @@ -/** - * This file includes polyfills needed by Angular and is loaded before the app. - * You can add your own extra polyfills to this file. - * - * This file is divided into 2 sections: - * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. - * 2. Application imports. Files imported after ZoneJS that should be loaded before your main - * file. - * - * The current setup is for so-called "evergreen" browsers; the last versions of browsers that - * automatically update themselves. This includes recent versions of Safari, Chrome (including - * Opera), Edge on the desktop, and iOS and Chrome on mobile. - * - * Learn more in https://angular.io/guide/browser-support - */ - -/*************************************************************************************************** - * BROWSER POLYFILLS - */ - -/** - * By default, zone.js will patch all possible macroTask and DomEvents - * user can disable parts of macroTask/DomEvents patch by setting following flags - * because those flags need to be set before `zone.js` being loaded, and webpack - * will put import in the top of bundle, so user need to create a separate file - * in this directory (for example: zone-flags.ts), and put the following flags - * into that file, and then add the following code before importing zone.js. - * import './zone-flags'; - * - * The flags allowed in zone-flags.ts are listed here. - * - * The following flags will work for all browsers. - * - * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame - * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick - * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames - * - * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js - * with the following flag, it will bypass `zone.js` patch for IE/Edge - * - * (window as any).__Zone_enable_cross_context_check = true; - * - */ - -/*************************************************************************************************** - * Zone JS is required by default for Angular itself. - */ -import 'zone.js'; // Included with Angular CLI. - -/*************************************************************************************************** - * APPLICATION IMPORTS - */ diff --git a/apps/ngrx/7-power-of-effect/src/styles.scss b/apps/ngrx/7-power-of-effect/src/styles.scss deleted file mode 100644 index 90d4ee0..0000000 --- a/apps/ngrx/7-power-of-effect/src/styles.scss +++ /dev/null @@ -1 +0,0 @@ -/* You can add global styles to this file, and also import other style files */ diff --git a/apps/ngrx/7-power-of-effect/tsconfig.app.json b/apps/ngrx/7-power-of-effect/tsconfig.app.json deleted file mode 100644 index 7a4dbc4..0000000 --- a/apps/ngrx/7-power-of-effect/tsconfig.app.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../dist/out-tsc", - "types": [], - "target": "ES2022", - "useDefineForClassFields": false - }, - "files": ["src/main.ts", "src/polyfills.ts"], - "include": ["src/**/*.d.ts"], - "exclude": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts"] -} diff --git a/apps/ngrx/7-power-of-effect/tsconfig.editor.json b/apps/ngrx/7-power-of-effect/tsconfig.editor.json deleted file mode 100644 index db1c012..0000000 --- a/apps/ngrx/7-power-of-effect/tsconfig.editor.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "include": [ - "**/*.ts", - "../../../libs/power-of-effect/backend/src/lib/fake-backend.service.ts" - ], - "compilerOptions": { - "types": [] - } -} diff --git a/apps/ngrx/7-power-of-effect/tsconfig.json b/apps/ngrx/7-power-of-effect/tsconfig.json deleted file mode 100644 index b2dbbf2..0000000 --- a/apps/ngrx/7-power-of-effect/tsconfig.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.app.json" - }, - { - "path": "./tsconfig.editor.json" - } - ], - "compilerOptions": { - "target": "es2020", - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true - }, - "angularCompilerOptions": { - "enableI18nLegacyMessageIdFormat": false, - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true - } -} diff --git a/apps/rxjs/11-high-order-operator-bug/src/app/app.component.ts b/apps/rxjs/11-high-order-operator-bug/src/app/app.component.ts index 4b50bab..fb80fb2 100644 --- a/apps/rxjs/11-high-order-operator-bug/src/app/app.component.ts +++ b/apps/rxjs/11-high-order-operator-bug/src/app/app.component.ts @@ -1,46 +1,44 @@ /* eslint-disable @angular-eslint/component-selector */ -import { AsyncPipe, NgFor } from '@angular/common'; -import { Component, Input, inject } from '@angular/core'; -import { BehaviorSubject, take } from 'rxjs'; +import { Component, inject, input, signal } from '@angular/core'; +import { take } from 'rxjs'; import { AppService } from './app.service'; import { TopicType } from './localDB.service'; @Component({ selector: 'button-delete-topic', - imports: [AsyncPipe], template: ` - -
{{ message$$ | async }}
+ +
{{ message() }}
`, }) export class ButtonDeleteComponent { - @Input() topic!: TopicType; + readonly topic = input.required(); - message$$ = new BehaviorSubject(''); + message = signal(''); private service = inject(AppService); deleteTopic() { this.service - .deleteOldTopics(this.topic) + .deleteOldTopics(this.topic()) .pipe(take(1)) .subscribe((result) => - this.message$$.next( + this.message.set( result - ? `All ${this.topic} have been deleted` - : `Error: deletion of some ${this.topic} failed`, + ? `All ${this.topic()} have been deleted` + : `Error: deletion of some ${this.topic()} failed`, ), ); } } @Component({ - imports: [AsyncPipe, NgFor, ButtonDeleteComponent], + imports: [ButtonDeleteComponent], selector: 'app-root', template: ` -
- {{ item.id }} - {{ item.topic }} -
+ @for (info of allInfo(); track info.id) { +
{{ info.id }} - {{ info.topic }}
+ } Delete Food Delete Sport @@ -50,5 +48,5 @@ export class ButtonDeleteComponent { export class AppComponent { private service = inject(AppService); - all$ = this.service.getAll$; + allInfo = this.service.getAllInfo; } diff --git a/apps/rxjs/11-high-order-operator-bug/src/app/app.service.ts b/apps/rxjs/11-high-order-operator-bug/src/app/app.service.ts index 7c81735..df2269a 100644 --- a/apps/rxjs/11-high-order-operator-bug/src/app/app.service.ts +++ b/apps/rxjs/11-high-order-operator-bug/src/app/app.service.ts @@ -1,23 +1,19 @@ import { inject, Injectable } from '@angular/core'; -import { merge, mergeMap, Observable, of, take } from 'rxjs'; +import { merge, Observable, of } from 'rxjs'; import { LocalDBService, TopicType } from './localDB.service'; @Injectable({ providedIn: 'root' }) export class AppService { private dbService = inject(LocalDBService); - getAll$ = this.dbService.infos$; + getAllInfo = this.dbService.infos; deleteOldTopics(type: TopicType): Observable { - return this.dbService.searchByType(type).pipe( - take(1), - mergeMap((topicToDelete) => - topicToDelete.length > 0 - ? topicToDelete - .map((t) => this.dbService.deleteOneTopic(t.id)) - .reduce((acc, curr) => merge(acc, curr), of(true)) - : of(true), - ), - ); + const infoByType = this.dbService.searchByType(type); + return infoByType.length > 0 + ? infoByType + .map((t) => this.dbService.deleteOneTopic(t.id)) + .reduce((acc, curr) => merge(acc, curr), of(true)) + : of(true); } } diff --git a/apps/rxjs/11-high-order-operator-bug/src/app/localDB.service.ts b/apps/rxjs/11-high-order-operator-bug/src/app/localDB.service.ts index d13d0ed..5a035e0 100644 --- a/apps/rxjs/11-high-order-operator-bug/src/app/localDB.service.ts +++ b/apps/rxjs/11-high-order-operator-bug/src/app/localDB.service.ts @@ -1,7 +1,6 @@ /* eslint-disable @typescript-eslint/member-ordering */ import { randomError } from '@angular-challenges/shared/utils'; -import { Injectable } from '@angular/core'; -import { ComponentStore } from '@ngrx/component-store'; +import { computed, Injectable, signal } from '@angular/core'; import { of } from 'rxjs'; export type TopicType = 'food' | 'book' | 'sport'; @@ -31,21 +30,17 @@ const initialState: DBState = { }; @Injectable({ providedIn: 'root' }) -export class LocalDBService extends ComponentStore { - constructor() { - super(initialState); - } +export class LocalDBService { + private state = signal(initialState); - infos$ = this.select((state) => state.infos); + infos = computed(() => this.state().infos); searchByType = (type: TopicType) => - this.select((state) => state.infos.filter((i) => i.topic === type)); + this.infos().filter((i) => i.topic === type); - deleteOne = this.updater( - (state, id: number): DBState => ({ - infos: state.infos.filter((i) => i.id !== id), - }), - ); + deleteOne = (id: number) => { + this.state.set({ infos: this.state().infos.filter((i) => i.id !== id) }); + }; deleteOneTopic = (id: number) => randomError({ diff --git a/docs/src/content/docs/challenges/ngrx/2-effect-selector.md b/docs/src/content/docs/challenges/ngrx/2-effect-selector.md deleted file mode 100644 index 84c573c..0000000 --- a/docs/src/content/docs/challenges/ngrx/2-effect-selector.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: 🟠 Effect vs Selector -description: Challenge 2 is about learning the difference between effects and selectors in NgRx -author: thomas-laforge -contributors: - - tomalaforge - - tomer953 - - svenson95 - - jdegand - - LMFinney -challengeNumber: 2 -command: ngrx-effect-vs-selector -blogLink: https://medium.com/@thomas.laforge/ngrx-effect-vs-reducer-vs-selector-58337ab59043 -videoLinks: - - link: https://youtu.be/7fr6JBRocQM - alt: Effect vs selector video by Amos Lucian Isaila - flag: ES -sidebar: - order: 113 ---- - -For this exercise, you will have a dashboard of activities displaying the name, the main teacher and a list of possible substitutes. - -## Information - -In NgRx, **selectors** is a very powerful tool that is often **misused**. You should use them as soon as you need to transform an already existing data in the store. - -- You shouldn't store **derived state**. This is error-prone because when your data changes, you will have to change it at multiple places => you should have only one place of truth with that data, and every transformation should be done in a **selector**. - -- Inside a component, you shouldn't transform a selector (using the map operator), and you shouldn't have to call a selector from a function in your view. The useful logic for preparing data for a component should be done in a **selector**. - -## Statement - -You will have to refactor this working example of a dashboard of activities. - -## Constraints - -- Only **one action** should be dispatched from a component (or none, if you can solve the problem with Effect lifecycle hooks). -- Status effect is useless. Using **combineLatest** should be a red flag. Effects are made for side effects, not for transforming data. That's a selector's role. -- Status state might not be useful; it's only a **derived state** of existing state. diff --git a/docs/src/content/docs/challenges/ngrx/7-power-effect.md b/docs/src/content/docs/challenges/ngrx/7-power-effect.md deleted file mode 100644 index 0dc43ac..0000000 --- a/docs/src/content/docs/challenges/ngrx/7-power-effect.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: 🔴 Power of Effect -description: Challenge 7 is about creating an NgRx effect with another Rxjs Hot observable -author: thomas-laforge -contributors: - - tomalaforge - - tomer953 - - jdegand - - LMFinney -challengeNumber: 7 -command: ngrx-power-of-effect -sidebar: - order: 206 ---- - -## Information - -This application exhibits local and global state confusion. Right now, a notification service is used to update the component lists of students and teachers. You need to add schools to this service, but you _cannot_. The school component uses its _own_ local state inside a `ComponentStore`. Thus, you are unable to dispatch an action in the notification service that the school component can respond to (remember, component stores do not have `actions`). So, how can we get around these issues? - -Injection tokens and NgRx effects can greatly help. - -`NgRx Effects` is a very powerful library developed by the NgRx team. Effects subscribe to a HOT Observable and listen for all events dispatched inside an application. `NgRx Effects` can subscribe to _any_ observable, which means we can wrap a hot observable inside an effect and add logic to it. You don't have to worry about the local or global state. Although you should be mindful of bad practices, when you refactor this application, you should make a determination of what should be a part of the local state and what should be a part of the global state. - -In this exercise, we will need to find a way to create a very powerful, scalable, and maintainable push message listener. - -### Step 1 - -Create an injection token to `inject` the push service inside each component. Injection tokens are very powerful. If you are unfamiliar with them, you may want to complete the [Injection token challenge](https://angular-challenges.vercel.app/challenges/angular/39-injection-token) first. This [article](https://netbasal.com/the-hidden-power-of-injectiontoken-factory-functions-in-angular-d42d5575859b) is also a great resource. - -_Eliminate_ the notification service. It is not extensible. Testing (not required for this challenge) the notification service would also be overly complicated. You would need to test each branching scenario. Injection tokens can easily be mocked. - -Since the notification service is global, all component lists update, even if a user is not on that route. We need to decouple that logic. The notification messages should display only on their respective routes. - -### Step 2 - -Create one NgRx effect or component store effect for each push type, and implement your logic. - -### Step 3 - -Show an [Angular Material snackbar](https://material.angular.io/components/snack-bar/overview) notification when an add event happens. Make each notification distinct. - -### Step 4 - -Load your effect only when necessary. - -The application contains a root route, a lazy loaded route, and a component with a local state (implemented with `ComponentStore`). diff --git a/libs/power-of-effect/backend/.eslintrc.json b/libs/power-of-effect/backend/.eslintrc.json deleted file mode 100644 index 9247a6e..0000000 --- a/libs/power-of-effect/backend/.eslintrc.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "extends": ["../../../.eslintrc.json"], - "ignorePatterns": ["!**/*"], - "overrides": [ - { - "files": ["*.ts"], - "extends": [ - "plugin:@nx/angular", - "plugin:@angular-eslint/template/process-inline-templates" - ], - "rules": { - "@angular-eslint/directive-selector": [ - "error", - { - "type": "attribute", - "prefix": "lib", - "style": "camelCase" - } - ], - "@angular-eslint/component-selector": [ - "error", - { - "type": "element", - "prefix": "lib", - "style": "kebab-case" - } - ] - } - }, - { - "files": ["*.html"], - "extends": ["plugin:@nx/angular-template"], - "rules": {} - } - ] -} diff --git a/libs/power-of-effect/backend/README.md b/libs/power-of-effect/backend/README.md deleted file mode 100644 index 9b29e57..0000000 --- a/libs/power-of-effect/backend/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# power-of-effect-backend - -This library was generated with [Nx](https://nx.dev). - -## Running unit tests - -Run `nx test power-of-effect-backend` to execute the unit tests. diff --git a/libs/power-of-effect/backend/jest.config.ts b/libs/power-of-effect/backend/jest.config.ts deleted file mode 100644 index 4efb3bb..0000000 --- a/libs/power-of-effect/backend/jest.config.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'power-of-effect-backend', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/test-setup.ts'], - globals: {}, - coverageDirectory: '../../../coverage/libs/power-of-effect/backend', - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/libs/power-of-effect/backend/project.json b/libs/power-of-effect/backend/project.json deleted file mode 100644 index 1525887..0000000 --- a/libs/power-of-effect/backend/project.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "power-of-effect-backend", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "library", - "sourceRoot": "libs/power-of-effect/backend/src", - "prefix": "lib", - "tags": [], - "targets": { - "test": { - "options": { - "passWithNoTests": true - }, - "configurations": { - "ci": { - "ci": true, - "coverage": true - } - } - } - } -} diff --git a/libs/power-of-effect/backend/src/index.ts b/libs/power-of-effect/backend/src/index.ts deleted file mode 100644 index b61dc61..0000000 --- a/libs/power-of-effect/backend/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './lib/fake-backend.service'; -export * from './lib/push.service'; diff --git a/libs/power-of-effect/backend/src/lib/fake-backend.service.ts b/libs/power-of-effect/backend/src/lib/fake-backend.service.ts deleted file mode 100644 index 89b0987..0000000 --- a/libs/power-of-effect/backend/src/lib/fake-backend.service.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { - randSchool, - randStudent, - randTeacher, -} from '@angular-challenges/power-of-effect/model'; -import { Injectable, inject } from '@angular/core'; -import { randCompanyName, randFirstName } from '@ngneat/falso'; -import { concatLatestFrom } from '@ngrx/operators'; -import { map, tap, timer } from 'rxjs'; -import { FakeDBService } from './fake-db.service'; -import { PushService } from './push.service'; - -@Injectable({ providedIn: 'root' }) -export class FakeBackendService { - private fakeDbService = inject(FakeDBService); - private pushService = inject(PushService); - - getAllTeachers = () => this.fakeDbService.teachers$; - getAllStudents = () => this.fakeDbService.students$; - getAllSchools = () => this.fakeDbService.schools$; - - start() { - this.fakeAddTeacher(); - this.fakeUpdateTeacher(); - this.fakeAddStudent(); - this.fakeUpdateStudent(); - this.fakeAddSchool(); - this.fakeUpdateSchool(); - } - - private fakeAddTeacher() { - timer(0, 4000) - .pipe( - map(() => randTeacher()), - tap((teacher) => this.pushService.pushData(teacher)), - tap((teacher) => this.fakeDbService.addTeacher(teacher)), - ) - .subscribe(); - } - - private fakeUpdateTeacher() { - timer(8000, 5000) - .pipe( - concatLatestFrom(() => this.fakeDbService.randomTeacher$), - map(([, teacher]) => ({ - ...teacher, - firstname: randFirstName(), - version: teacher.version + 1, - })), - tap((teacher) => this.pushService.pushData(teacher)), - tap((teacher) => this.fakeDbService.updateTeacher(teacher)), - ) - .subscribe(); - } - - private fakeAddStudent() { - timer(0, 2000) - .pipe( - map(() => randStudent()), - tap((student) => this.pushService.pushData(student)), - tap((student) => this.fakeDbService.addStudent(student)), - ) - .subscribe(); - } - - private fakeUpdateStudent() { - timer(8000, 6000) - .pipe( - concatLatestFrom(() => this.fakeDbService.randomStudents$), - map(([, student]) => ({ - ...student, - firstname: randFirstName(), - version: student.version + 1, - })), - tap((student) => this.pushService.pushData(student)), - tap((student) => this.fakeDbService.updateSudent(student)), - ) - .subscribe(); - } - - private fakeAddSchool() { - timer(0, 2000) - .pipe( - map(() => randSchool()), - tap((school) => this.pushService.pushData(school)), - tap((school) => this.fakeDbService.addSchool(school)), - ) - .subscribe(); - } - - private fakeUpdateSchool() { - timer(8000, 4000) - .pipe( - concatLatestFrom(() => this.fakeDbService.randomSchool$), - map(([, school]) => ({ - ...school, - name: randCompanyName(), - version: school.version + 1, - })), - tap((school) => this.pushService.pushData(school)), - tap((school) => this.fakeDbService.updateSchool(school)), - ) - .subscribe(); - } -} diff --git a/libs/power-of-effect/backend/src/lib/fake-db.service.ts b/libs/power-of-effect/backend/src/lib/fake-db.service.ts deleted file mode 100644 index b8225c9..0000000 --- a/libs/power-of-effect/backend/src/lib/fake-db.service.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { - School, - Student, - Teacher, -} from '@angular-challenges/power-of-effect/model'; -import { Injectable } from '@angular/core'; -import { randNumber } from '@ngneat/falso'; -import { ComponentStore } from '@ngrx/component-store'; - -interface AppState { - teachers: Teacher[]; - students: Student[]; - schools: School[]; -} - -@Injectable({ providedIn: 'root' }) -export class FakeDBService extends ComponentStore { - readonly teachers$ = this.select((state) => state.teachers); - readonly randomTeacher$ = this.select( - this.teachers$, - (teachers) => teachers[randNumber({ max: teachers.length - 1 })], - ); - - readonly students$ = this.select((state) => state.students); - readonly randomStudents$ = this.select( - this.students$, - (students) => students[randNumber({ max: students.length - 1 })], - ); - - readonly schools$ = this.select((state) => state.schools); - readonly randomSchool$ = this.select( - this.schools$, - (schools) => schools[randNumber({ max: schools.length - 1 })], - ); - - constructor() { - super({ teachers: [], students: [], schools: [] }); - } - - addTeacher = this.updater( - (state, teacher: Teacher): AppState => ({ - ...state, - teachers: [...state.teachers, teacher], - }), - ); - - updateTeacher = this.updater( - (state, teacher: Teacher): AppState => ({ - ...state, - teachers: state.teachers.map((t) => (t.id === teacher.id ? teacher : t)), - }), - ); - - addStudent = this.updater( - (state, student: Student): AppState => ({ - ...state, - students: [...state.students, student], - }), - ); - - updateSudent = this.updater( - (state, student: Student): AppState => ({ - ...state, - students: state.students.map((t) => (t.id === student.id ? student : t)), - }), - ); - - addSchool = this.updater( - (state, school: School): AppState => ({ - ...state, - schools: [...state.schools, school], - }), - ); - - updateSchool = this.updater( - (state, school: School): AppState => ({ - ...state, - schools: state.schools.map((t) => (t.id === school.id ? school : t)), - }), - ); -} diff --git a/libs/power-of-effect/backend/src/lib/push.service.ts b/libs/power-of-effect/backend/src/lib/push.service.ts deleted file mode 100644 index b214acd..0000000 --- a/libs/power-of-effect/backend/src/lib/push.service.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Push } from '@angular-challenges/power-of-effect/model'; -import { Injectable } from '@angular/core'; -import { BehaviorSubject } from 'rxjs'; - -@Injectable({ providedIn: 'root' }) -export class PushService { - private notificationSubject = new BehaviorSubject( - undefined, - ); - notification$ = this.notificationSubject.asObservable(); - - pushData(data: Push) { - this.notificationSubject.next(data); - } -} diff --git a/libs/power-of-effect/backend/src/test-setup.ts b/libs/power-of-effect/backend/src/test-setup.ts deleted file mode 100644 index 1100b3e..0000000 --- a/libs/power-of-effect/backend/src/test-setup.ts +++ /dev/null @@ -1 +0,0 @@ -import 'jest-preset-angular/setup-jest'; diff --git a/libs/power-of-effect/backend/tsconfig.json b/libs/power-of-effect/backend/tsconfig.json deleted file mode 100644 index 7504c34..0000000 --- a/libs/power-of-effect/backend/tsconfig.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.lib.json" - }, - { - "path": "./tsconfig.spec.json" - } - ], - "compilerOptions": { - "target": "es2020", - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true - }, - "angularCompilerOptions": { - "enableI18nLegacyMessageIdFormat": false, - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true - } -} diff --git a/libs/power-of-effect/backend/tsconfig.lib.json b/libs/power-of-effect/backend/tsconfig.lib.json deleted file mode 100644 index dd189dc..0000000 --- a/libs/power-of-effect/backend/tsconfig.lib.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../dist/out-tsc", - "declaration": true, - "declarationMap": true, - "inlineSources": true, - "types": [] - }, - "exclude": [ - "src/test-setup.ts", - "**/*.spec.ts", - "jest.config.ts", - "**/*.test.ts" - ], - "include": ["**/*.ts"] -} diff --git a/libs/power-of-effect/backend/tsconfig.spec.json b/libs/power-of-effect/backend/tsconfig.spec.json deleted file mode 100644 index 7aa46d8..0000000 --- a/libs/power-of-effect/backend/tsconfig.spec.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../dist/out-tsc", - "module": "commonjs", - "types": ["jest", "node"] - }, - "files": ["src/test-setup.ts"], - "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] -} diff --git a/libs/power-of-effect/model/.eslintrc.json b/libs/power-of-effect/model/.eslintrc.json deleted file mode 100644 index 9247a6e..0000000 --- a/libs/power-of-effect/model/.eslintrc.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "extends": ["../../../.eslintrc.json"], - "ignorePatterns": ["!**/*"], - "overrides": [ - { - "files": ["*.ts"], - "extends": [ - "plugin:@nx/angular", - "plugin:@angular-eslint/template/process-inline-templates" - ], - "rules": { - "@angular-eslint/directive-selector": [ - "error", - { - "type": "attribute", - "prefix": "lib", - "style": "camelCase" - } - ], - "@angular-eslint/component-selector": [ - "error", - { - "type": "element", - "prefix": "lib", - "style": "kebab-case" - } - ] - } - }, - { - "files": ["*.html"], - "extends": ["plugin:@nx/angular-template"], - "rules": {} - } - ] -} diff --git a/libs/power-of-effect/model/README.md b/libs/power-of-effect/model/README.md deleted file mode 100644 index 2c8dd7f..0000000 --- a/libs/power-of-effect/model/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# power-of-effect-model - -This library was generated with [Nx](https://nx.dev). - -## Running unit tests - -Run `nx test power-of-effect-model` to execute the unit tests. diff --git a/libs/power-of-effect/model/jest.config.ts b/libs/power-of-effect/model/jest.config.ts deleted file mode 100644 index aadbfeb..0000000 --- a/libs/power-of-effect/model/jest.config.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'power-of-effect-model', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/test-setup.ts'], - globals: {}, - coverageDirectory: '../../../coverage/libs/power-of-effect/model', - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/libs/power-of-effect/model/project.json b/libs/power-of-effect/model/project.json deleted file mode 100644 index 020f968..0000000 --- a/libs/power-of-effect/model/project.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "power-of-effect-model", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "library", - "sourceRoot": "libs/power-of-effect/model/src", - "prefix": "lib", - "tags": [], - "targets": { - "test": { - "options": { - "passWithNoTests": true - }, - "configurations": { - "ci": { - "ci": true, - "coverage": true - } - } - } - } -} diff --git a/libs/power-of-effect/model/src/index.ts b/libs/power-of-effect/model/src/index.ts deleted file mode 100644 index d866f8a..0000000 --- a/libs/power-of-effect/model/src/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './lib/push.model'; -export * from './lib/school.model'; -export * from './lib/student.model'; -export * from './lib/teacher.model'; diff --git a/libs/power-of-effect/model/src/lib/push.model.ts b/libs/power-of-effect/model/src/lib/push.model.ts deleted file mode 100644 index 5f1d5f2..0000000 --- a/libs/power-of-effect/model/src/lib/push.model.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type PushType = 'teacher' | 'student' | 'school'; - -export interface Push { - type: PushType; -} diff --git a/libs/power-of-effect/model/src/lib/school.model.ts b/libs/power-of-effect/model/src/lib/school.model.ts deleted file mode 100644 index d27ea71..0000000 --- a/libs/power-of-effect/model/src/lib/school.model.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { incrementalNumber, randCompanyName } from '@ngneat/falso'; -import { Push } from './push.model'; - -export interface School extends Push { - id: number; - name: string; - version: number; -} - -const factorySchool = incrementalNumber(); - -export const randSchool = (): School => ({ - id: factorySchool(), - name: randCompanyName(), - version: 0, - type: 'school', -}); - -export const isSchool = (notif: Push): notif is School => { - return notif.type === 'school'; -}; diff --git a/libs/power-of-effect/model/src/lib/student.model.ts b/libs/power-of-effect/model/src/lib/student.model.ts deleted file mode 100644 index 6360b93..0000000 --- a/libs/power-of-effect/model/src/lib/student.model.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { incrementalNumber, randFirstName, randLastName } from '@ngneat/falso'; -import { Push } from './push.model'; - -export interface Student extends Push { - id: number; - firstname: string; - lastname: string; - version: number; -} - -const factoryStudent = incrementalNumber(); - -export const randStudent = (): Student => ({ - id: factoryStudent(), - firstname: randFirstName(), - lastname: randLastName(), - version: 0, - type: 'student', -}); - -export const isStudent = (notif: Push): notif is Student => { - return notif.type === 'student'; -}; diff --git a/libs/power-of-effect/model/src/lib/teacher.model.ts b/libs/power-of-effect/model/src/lib/teacher.model.ts deleted file mode 100644 index f7b1ad6..0000000 --- a/libs/power-of-effect/model/src/lib/teacher.model.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { incrementalNumber, randFirstName, randLastName } from '@ngneat/falso'; -import { Push } from './push.model'; - -export interface Teacher extends Push { - id: number; - firstname: string; - lastname: string; - version: number; -} - -const factoryTeacher = incrementalNumber(); - -export const randTeacher = (): Teacher => ({ - id: factoryTeacher(), - firstname: randFirstName(), - lastname: randLastName(), - version: 0, - type: 'teacher', -}); - -export const isTeacher = (notif: Push): notif is Teacher => { - return notif.type === 'teacher'; -}; diff --git a/libs/power-of-effect/model/src/test-setup.ts b/libs/power-of-effect/model/src/test-setup.ts deleted file mode 100644 index 1100b3e..0000000 --- a/libs/power-of-effect/model/src/test-setup.ts +++ /dev/null @@ -1 +0,0 @@ -import 'jest-preset-angular/setup-jest'; diff --git a/libs/power-of-effect/model/tsconfig.json b/libs/power-of-effect/model/tsconfig.json deleted file mode 100644 index 7504c34..0000000 --- a/libs/power-of-effect/model/tsconfig.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.lib.json" - }, - { - "path": "./tsconfig.spec.json" - } - ], - "compilerOptions": { - "target": "es2020", - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true - }, - "angularCompilerOptions": { - "enableI18nLegacyMessageIdFormat": false, - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true - } -} diff --git a/libs/power-of-effect/model/tsconfig.lib.json b/libs/power-of-effect/model/tsconfig.lib.json deleted file mode 100644 index dd189dc..0000000 --- a/libs/power-of-effect/model/tsconfig.lib.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../dist/out-tsc", - "declaration": true, - "declarationMap": true, - "inlineSources": true, - "types": [] - }, - "exclude": [ - "src/test-setup.ts", - "**/*.spec.ts", - "jest.config.ts", - "**/*.test.ts" - ], - "include": ["**/*.ts"] -} diff --git a/libs/power-of-effect/model/tsconfig.spec.json b/libs/power-of-effect/model/tsconfig.spec.json deleted file mode 100644 index 7aa46d8..0000000 --- a/libs/power-of-effect/model/tsconfig.spec.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../dist/out-tsc", - "module": "commonjs", - "types": ["jest", "node"] - }, - "files": ["src/test-setup.ts"], - "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] -} diff --git a/libs/shared/ngrx-callstate-store/.eslintrc.json b/libs/shared/ngrx-callstate-store/.eslintrc.json deleted file mode 100644 index 9247a6e..0000000 --- a/libs/shared/ngrx-callstate-store/.eslintrc.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "extends": ["../../../.eslintrc.json"], - "ignorePatterns": ["!**/*"], - "overrides": [ - { - "files": ["*.ts"], - "extends": [ - "plugin:@nx/angular", - "plugin:@angular-eslint/template/process-inline-templates" - ], - "rules": { - "@angular-eslint/directive-selector": [ - "error", - { - "type": "attribute", - "prefix": "lib", - "style": "camelCase" - } - ], - "@angular-eslint/component-selector": [ - "error", - { - "type": "element", - "prefix": "lib", - "style": "kebab-case" - } - ] - } - }, - { - "files": ["*.html"], - "extends": ["plugin:@nx/angular-template"], - "rules": {} - } - ] -} diff --git a/libs/shared/ngrx-callstate-store/README.md b/libs/shared/ngrx-callstate-store/README.md deleted file mode 100644 index 0bcdc77..0000000 --- a/libs/shared/ngrx-callstate-store/README.md +++ /dev/null @@ -1,231 +0,0 @@ -# NgRx CallState ComponentStore - -NgRx CallState ComponentStore is a small library that extends the **@Ngrx/component-store** by adding a loading and error state to your custom state. - -## Installation - -Requires @Ngrx/component-store - -Yarn: - -```bash -yarn add @tomalaforge/ngrx-callstate-store -``` - -NPM: - -```bash -npm i @tomalaforge/ngrx-callstate-store -``` - -## Introduction - -When making XHR calls or any asynschronous tasks, you always need a loading or error state. By using `CallStateComponentStore`, you can easily manage the loading and error states of your async tasks, which makes your code more organized and maintainable. - -## Example - -```typescript -@Injectable() -export class AppStore extends CallStateComponentStore<{todos: Todo[]}> { - readonly todos$ = this.select((state) => state.todos); - - readonly vm$ = this.select({ - todos: this.todos$, - loading: this.loading$, - }, {debounce: true}); - - constructor(private todoService: TodoService) { - super({ todos: [] }); - } - - readonly fetchTodo = this.effect( - pipe( - tap(() => this.startLoading()), - switchMap(() => - this.todoService.getAllTodo().pipe( - tapResponse( - (todos) => this.stopLoading({ todos }), - (error: unknown) => this.handleError(error, {todos: []}) - ) - ) - ) - ) - ); -``` - -By extending your class with `CallStateComponentStore`, a `CallState` property is added to your state. - -> You don't need to provide a state if you only want to use the `CallState` property. - -```typescript -export type LoadingState = 'INIT' | 'LOADING' | 'LOADED'; - -export interface ErrorState { - error: CustomError; -} - -export type CallState = LoadingState | ErrorState; -``` - -> You can override [`CustomError`](#errorstate) as needed. - -## API - -### initialization - -##### setInitState - -The `setInitState` method lets you initialize your custom state if you are not using the constructor. - -```typescript -setInitState = (state: T): void -``` - -### updater - -##### startLoading - -The `startLoading` method sets the `CallState` property to the `LOADING` state. You can pass optional state properties if you want to patch your own state. - -```typescript -startLoading = (state: Optional): void -``` - -##### stopLoading - -The `stopLoading` method sets the `CallState` to the `LOADED` state. You can pass an optional state properties as well. - -```typescript -stopLoading = (state: Optional): void -``` - -##### updateCallState - -The `updateCallState` method updates the callState with the inputed value. - -```typescript -updateCallState = (callState: CallState): void -``` - -##### handleError - -The `handleError` method handles errors. You can pass an optional state. - -```typescript -handleError = (error: unknown, state: Optional): void -``` - -### selector - -##### isLoading$ - -`isLoading$` return a boolean, true if state is loading, false otherwise - -##### isLoadingWithFlicker$ - -`isLoadingWithFlicker$` return the same as `isLoading$` but with a small delay. This can be useful when you don't want your page to flicker. - -##### isLoaded$ - -`isLoaded$` return a boolean, true if state is loaded, false otherwise - -##### callState$ - -`isLoading$` return the `CallState` - -##### error$ - -`isLoading$` return your error message using the `getErrorMessage` of your `ErrorState`. [(see below)](#errorstate) - ---- - -### Customize the library - -##### ErrorState - -You can provide your own implementation of The `ErrorState` by implementing `ErrorHandler` - -```typescript -export interface ErrorHandler { - toError: (error: unknown) => T; - getErrorMessage: (error?: T) => string | undefined; -} -``` - -The `toError` method converts the error input into the desired error object. -The `getErrorMessage` method returns the well-formed error message that you want to display to your user. - -The current implementation is as follow: - -```typescript -export const UNKNOWN_ERROR_CAUSE = 'UNKNOWN_ERROR'; -export const UNKNOWN_ERROR_MESSAGE = 'unknown error occured'; - -export class CallStateError { - name: string; - message: string; - stack?: string; - - constructor(name = '', message = '') { - this.name = name; - this.message = message; - } -} - -export class CallStateErrorHandler implements ErrorHandler { - toError = (error: unknown): CallStateError => { - if (error instanceof CallStateError) return error; - if (error instanceof Error) return new CallStateError(error.name, error.message); - return new CallStateError(UNKNOWN_ERROR_CAUSE, UNKNOWN_ERROR_MESSAGE); - }; - - getErrorMessage = (error?: CallStateError): string | undefined => { - return error?.message; - }; -} -``` - -Let's say you want to customize it as follow: - -```typescript -export const UNKNOWN_ERROR_MESSAGE = 'unknown error occured'; - -export class MyError { - message: string; - code: number - - constructor(message = '', code = 404) { - this.message = message; - this.code = code; - } -} - -export class MyErrorHandler implements ErrorHandler { - toError = (error: unknown): MyError => { - if (error instanceof MyError) return error; - if (error instanceof Error) - return new MyError(error.message); - return new MyError(UNKNOWN_ERROR_MESSAGE); - }; - - getErrorMessage = (error?: MyError): string | undefined => { - return error.code error?.message; - }; -} -``` - -Now to override the default implementation, you need to provide it as follow : - -```typescript -provideErrorHandler(MyErrorHandler); -``` - -> You can provide it at root level to apply it to your whole application or at the component level for more specific implementation. - -##### Flicker Delay - -The default delay is 300ms but you can override it by providing it as follow: - -```typescript -provideFlickerDelay(500); -``` diff --git a/libs/shared/ngrx-callstate-store/jest.config.ts b/libs/shared/ngrx-callstate-store/jest.config.ts deleted file mode 100644 index 6c6eb92..0000000 --- a/libs/shared/ngrx-callstate-store/jest.config.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-disable */ -export default { - displayName: 'shared-ngrx-callstate-store', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/test-setup.ts'], - globals: {}, - coverageDirectory: '../../../coverage/libs/shared/ngrx-callstate-store', - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/libs/shared/ngrx-callstate-store/ng-package.json b/libs/shared/ngrx-callstate-store/ng-package.json deleted file mode 100644 index a94c8bd..0000000 --- a/libs/shared/ngrx-callstate-store/ng-package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", - "dest": "../../../dist/libs/shared/ngrx-callstate-store", - "lib": { - "entryFile": "src/index.ts" - } -} diff --git a/libs/shared/ngrx-callstate-store/package.json b/libs/shared/ngrx-callstate-store/package.json deleted file mode 100644 index bc4bbb0..0000000 --- a/libs/shared/ngrx-callstate-store/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "@tomalaforge/ngrx-callstate-store", - "version": "0.0.4", - "description": "Enhance NgRx component-store by providing a loading/error state", - "publishConfig": { - "access": "public" - }, - "repository": { - "type": "git", - "url": "https://github.com/tomalaforge/angular-challenges/tree/main/libs/shared/ngrx-callstate-store" - }, - "keywords": [ - "angular", - "state", - "ngrx/component-store" - ], - "author": { - "name": "Thomas Laforge" - }, - "peerDependencies": { - "@angular/common": "^15.0.0", - "@angular/core": "^15.0.0" - }, - "dependencies": { - "tslib": "^2.3.0" - } -} diff --git a/libs/shared/ngrx-callstate-store/project.json b/libs/shared/ngrx-callstate-store/project.json deleted file mode 100644 index 02eac7e..0000000 --- a/libs/shared/ngrx-callstate-store/project.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "shared-ngrx-callstate-store", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "projectType": "library", - "sourceRoot": "libs/shared/ngrx-callstate-store/src", - "prefix": "lib", - "tags": [], - "targets": { - "build": { - "executor": "@nx/angular:package", - "outputs": ["{workspaceRoot}/dist/{projectRoot}"], - "options": { - "project": "libs/shared/ngrx-callstate-store/ng-package.json" - }, - "configurations": { - "production": { - "tsConfig": "libs/shared/ngrx-callstate-store/tsconfig.lib.prod.json" - }, - "development": { - "tsConfig": "libs/shared/ngrx-callstate-store/tsconfig.lib.json" - } - }, - "defaultConfiguration": "production" - }, - "test": { - "options": { - "passWithNoTests": true - }, - "configurations": { - "ci": { - "ci": true, - "coverage": true - } - } - } - } -} diff --git a/libs/shared/ngrx-callstate-store/src/index.ts b/libs/shared/ngrx-callstate-store/src/index.ts deleted file mode 100644 index 1de3f04..0000000 --- a/libs/shared/ngrx-callstate-store/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './lib/call-state-component-store'; -export * from './lib/external.model'; diff --git a/libs/shared/ngrx-callstate-store/src/lib/call-state-component-store.ts b/libs/shared/ngrx-callstate-store/src/lib/call-state-component-store.ts deleted file mode 100644 index 26c6e69..0000000 --- a/libs/shared/ngrx-callstate-store/src/lib/call-state-component-store.ts +++ /dev/null @@ -1,105 +0,0 @@ -/* eslint-disable @typescript-eslint/ban-types */ -import { - inject, - Inject, - Injectable, - InjectionToken, - Optional, -} from '@angular/core'; -import { ComponentStore } from '@ngrx/component-store'; -import { Observable, of, switchMap } from 'rxjs'; -import { - CallState, - CallStateError, - getErrorCallState, -} from './call-state.model'; -import { ERROR_TOKEN, FLICKER_TIME } from './external.model'; -import { nonFlickerLoader } from './non-flicker-loader'; - -export const INITIAL_TOKEN = new InjectionToken('initial data'); - -export interface CallStateComponentState { - callState: CallState; -} - -@Injectable() -export class CallStateComponentStore< - U extends object | void = void, - T extends - | (U & CallStateComponentState) - | CallStateComponentState = U extends void - ? CallStateComponentState - : U & CallStateComponentState, -> extends ComponentStore { - private error = inject(ERROR_TOKEN); - private flickerTime = inject(FLICKER_TIME); - - constructor(@Inject(INITIAL_TOKEN) @Optional() initialState: U) { - super({ callState: 'INIT', ...initialState } as T); - } - - readonly isLoading$: Observable = this.select( - (state) => state.callState === 'LOADING', - ); - - readonly isLoadingWithFlicker$: Observable = this.select( - (state) => state.callState === 'LOADING', - ).pipe( - switchMap((loading) => nonFlickerLoader(of(loading), this.flickerTime)), - ); - - readonly isLoaded$: Observable = this.select( - (state) => state.callState === 'LOADED', - ).pipe(switchMap((loaded) => of(loaded))); - - readonly callState$ = this.select((state) => state.callState); - - readonly error$: Observable = this.select((state) => - this.error.getErrorMessage(getErrorCallState(state.callState)), - ); - - readonly updateCallState = this.updater( - (state, callState: CallState | undefined): T => { - return { - ...(state as object), - callState: callState ?? 'LOADED', - } as T; - }, - ); - - readonly startLoading = this.updater( - (state, patchedState: Partial | void): T => { - return { - ...(state as object), - ...patchedState, - callState: 'LOADING', - } as T; - }, - ); - - readonly stopLoading = this.updater( - (state, patchedState: Partial | void): T => { - return { - ...(state as object), - ...patchedState, - callState: 'LOADED', - } as T; - }, - ); - - protected handleError( - error: unknown, - patchedState: Partial = {}, - ): CallStateError { - const err = this.error.toError(error); - this.patchState({ - callState: { error: err }, - ...patchedState, - } as Partial); - return err; - } - - setInitState(initialState: U) { - this.setState({ callState: 'INIT', ...initialState } as T); - } -} diff --git a/libs/shared/ngrx-callstate-store/src/lib/call-state.model.ts b/libs/shared/ngrx-callstate-store/src/lib/call-state.model.ts deleted file mode 100644 index 0747551..0000000 --- a/libs/shared/ngrx-callstate-store/src/lib/call-state.model.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { CustomError, ErrorHandler } from './external.model'; - -export type LoadingState = 'INIT' | 'LOADING' | 'LOADED'; - -export const UNKNOWN_ERROR_CAUSE = 'UNKNOWN_ERROR'; -export const UNKNOWN_ERROR_MESSAGE = 'unknown error occured'; - -export class CallStateError { - name: string; - message: string; - stack?: string; - - constructor(name = '', message = '') { - this.name = name; - this.message = message; - } -} - -export class CallStateErrorHandler implements ErrorHandler { - toError = (error: unknown): CallStateError => { - if (error instanceof CallStateError) return error; - if (error instanceof Error) - return new CallStateError(error.name, error.message); - return new CallStateError(UNKNOWN_ERROR_CAUSE, UNKNOWN_ERROR_MESSAGE); - }; - - getErrorMessage = (error?: CallStateError): string | undefined => { - return error?.message; - }; -} - -export interface ErrorState { - error: CustomError; -} - -export type CallState = LoadingState | ErrorState; - -export const getErrorCallState = ( - callState: CallState, -): CustomError | undefined => { - if (isErrorState(callState)) { - return callState.error; - } - return undefined; -}; - -export const isLoadedOrInError = (callState: CallState): boolean => - callState === 'LOADED' || isErrorState(callState); - -export const isErrorState = (callState: CallState): callState is ErrorState => - Object.prototype.hasOwnProperty.call(callState, 'error'); diff --git a/libs/shared/ngrx-callstate-store/src/lib/external.model.ts b/libs/shared/ngrx-callstate-store/src/lib/external.model.ts deleted file mode 100644 index 2df16f0..0000000 --- a/libs/shared/ngrx-callstate-store/src/lib/external.model.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* eslint-disable @typescript-eslint/no-empty-interface */ -import { - ClassProvider, - InjectionToken, - Type, - ValueProvider, -} from '@angular/core'; -import { CallStateErrorHandler } from './call-state.model'; - -export interface ErrorHandler { - toError: (error: unknown) => T; - getErrorMessage: (error?: T) => string | undefined; -} - -export interface CustomError {} - -export const ERROR_TOKEN = new InjectionToken>('error', { - factory: () => new CallStateErrorHandler(), -}); - -export const provideErrorHandler = >( - errorHandlerClass: Type, -): ClassProvider => ({ provide: ERROR_TOKEN, useClass: errorHandlerClass }); - -export const FLICKER_TIME = new InjectionToken('flicker', { - factory: () => 300, -}); - -export const provideFlickerDelay = (delay: number): ValueProvider => ({ - provide: FLICKER_TIME, - useValue: delay, -}); diff --git a/libs/shared/ngrx-callstate-store/src/lib/non-flicker-loader.ts b/libs/shared/ngrx-callstate-store/src/lib/non-flicker-loader.ts deleted file mode 100644 index bcbf460..0000000 --- a/libs/shared/ngrx-callstate-store/src/lib/non-flicker-loader.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { combineLatest, map, mapTo, Observable, startWith, timer } from 'rxjs'; - -/** - * Delay the first emition of data$ value. Instead, it emits "true" until duration is elapsed - */ -export const nonFlickerLoader = ( - data$: Observable, - duration = 300, -): Observable => { - const isTrueWhileDuration$ = timer(duration).pipe( - mapTo(false), - startWith(true), - ); - - return combineLatest([data$, isTrueWhileDuration$]).pipe( - map(([data, isTrueWhileDuration]) => - isTrueWhileDuration ? isTrueWhileDuration : data, - ), - ); -}; diff --git a/libs/shared/ngrx-callstate-store/src/test-setup.ts b/libs/shared/ngrx-callstate-store/src/test-setup.ts deleted file mode 100644 index 1100b3e..0000000 --- a/libs/shared/ngrx-callstate-store/src/test-setup.ts +++ /dev/null @@ -1 +0,0 @@ -import 'jest-preset-angular/setup-jest'; diff --git a/libs/shared/ngrx-callstate-store/tsconfig.json b/libs/shared/ngrx-callstate-store/tsconfig.json deleted file mode 100644 index 888e0b0..0000000 --- a/libs/shared/ngrx-callstate-store/tsconfig.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "extends": "../../../tsconfig.base.json", - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.lib.json" - }, - { - "path": "./tsconfig.lib.prod.json" - }, - { - "path": "./tsconfig.spec.json" - } - ], - "compilerOptions": { - "target": "es2022", - "useDefineForClassFields": false, - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true - }, - "angularCompilerOptions": { - "enableI18nLegacyMessageIdFormat": false, - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true - } -} diff --git a/libs/shared/ngrx-callstate-store/tsconfig.lib.json b/libs/shared/ngrx-callstate-store/tsconfig.lib.json deleted file mode 100644 index dd189dc..0000000 --- a/libs/shared/ngrx-callstate-store/tsconfig.lib.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../dist/out-tsc", - "declaration": true, - "declarationMap": true, - "inlineSources": true, - "types": [] - }, - "exclude": [ - "src/test-setup.ts", - "**/*.spec.ts", - "jest.config.ts", - "**/*.test.ts" - ], - "include": ["**/*.ts"] -} diff --git a/libs/shared/ngrx-callstate-store/tsconfig.lib.prod.json b/libs/shared/ngrx-callstate-store/tsconfig.lib.prod.json deleted file mode 100644 index 2a2faa8..0000000 --- a/libs/shared/ngrx-callstate-store/tsconfig.lib.prod.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "./tsconfig.lib.json", - "compilerOptions": { - "declarationMap": false - }, - "angularCompilerOptions": { - "compilationMode": "partial" - } -} diff --git a/libs/shared/ngrx-callstate-store/tsconfig.spec.json b/libs/shared/ngrx-callstate-store/tsconfig.spec.json deleted file mode 100644 index 7aa46d8..0000000 --- a/libs/shared/ngrx-callstate-store/tsconfig.spec.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../dist/out-tsc", - "module": "commonjs", - "types": ["jest", "node"] - }, - "files": ["src/test-setup.ts"], - "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] -} diff --git a/tsconfig.base.json b/tsconfig.base.json index 7b8f6b3..53c7f60 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -57,12 +57,6 @@ "@angular-challenges/module-to-standalone/user/shell": [ "libs/module-to-standalone/user/shell/src/index.ts" ], - "@angular-challenges/power-of-effect/backend": [ - "libs/power-of-effect/backend/src/index.ts" - ], - "@angular-challenges/power-of-effect/model": [ - "libs/power-of-effect/model/src/index.ts" - ], "@angular-challenges/shared/directives": [ "libs/shared/directives/src/index.ts" ], @@ -77,9 +71,6 @@ "@angular-challenges/testing-table/model": [ "libs/testing-table/model/src/index.ts" ], - "@tomalaforge/ngrx-callstate-store": [ - "libs/shared/ngrx-callstate-store/src/index.ts" - ], "angular-master-dependency-injection": [ "apps/angular/16-master-dependency-injection/src/index.ts" ]