(studentsFeatureKey);
+
+export const { selectAll } = studentAdapter.getSelectors();
+
+const selectStudents = createSelector(selectStudentState, selectAll);
+
+export const StudentSelectors = {
+ selectStudents,
+};
diff --git a/apps/ngrx-notification/src/app/student.component.ts b/apps/ngrx-notification/src/app/student/student.component.ts
similarity index 61%
rename from apps/ngrx-notification/src/app/student.component.ts
rename to apps/ngrx-notification/src/app/student/student.component.ts
index fdff994..bbc45bf 100644
--- a/apps/ngrx-notification/src/app/student.component.ts
+++ b/apps/ngrx-notification/src/app/student/student.component.ts
@@ -1,7 +1,8 @@
/* eslint-disable @angular-eslint/component-selector */
import { AsyncPipe, NgFor } from '@angular/common';
-import { Component } from '@angular/core';
-import { StudentStore } from './data-access/student.store';
+import { Component, inject } from '@angular/core';
+import { Store } from '@ngrx/store';
+import { StudentSelectors } from './store/student.selectors';
@Component({
standalone: true,
@@ -10,7 +11,7 @@ import { StudentStore } from './data-access/student.store';
template: `
STUDENTS
- {{ student.firstname }}
+ {{ student.firstname }} {{ student.lastname }} - {{ student.version }}
`,
styles: [
@@ -26,7 +27,6 @@ import { StudentStore } from './data-access/student.store';
],
})
export class StudentComponent {
- students$ = this.studentStore.students$;
-
- constructor(private studentStore: StudentStore) {}
+ private store = inject(Store);
+ students$ = this.store.select(StudentSelectors.selectStudents);
}
diff --git a/apps/ngrx-notification/src/app/teacher/store/teacher.actions.ts b/apps/ngrx-notification/src/app/teacher/store/teacher.actions.ts
new file mode 100644
index 0000000..ff41af3
--- /dev/null
+++ b/apps/ngrx-notification/src/app/teacher/store/teacher.actions.ts
@@ -0,0 +1,10 @@
+import { Teacher } from '@angular-challenges/ngrx-notification/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-notification/src/app/teacher/store/teacher.effects.ts b/apps/ngrx-notification/src/app/teacher/store/teacher.effects.ts
new file mode 100644
index 0000000..9eca53b
--- /dev/null
+++ b/apps/ngrx-notification/src/app/teacher/store/teacher.effects.ts
@@ -0,0 +1,23 @@
+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-notification/src/app/teacher/store/teacher.reducer.ts b/apps/ngrx-notification/src/app/teacher/store/teacher.reducer.ts
new file mode 100644
index 0000000..ecc95a0
--- /dev/null
+++ b/apps/ngrx-notification/src/app/teacher/store/teacher.reducer.ts
@@ -0,0 +1,24 @@
+import { Teacher } from '@angular-challenges/ngrx-notification/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-notification/src/app/teacher/store/teacher.selectors.ts b/apps/ngrx-notification/src/app/teacher/store/teacher.selectors.ts
new file mode 100644
index 0000000..f9fc4f1
--- /dev/null
+++ b/apps/ngrx-notification/src/app/teacher/store/teacher.selectors.ts
@@ -0,0 +1,17 @@
+import { createFeatureSelector, createSelector } from '@ngrx/store';
+import {
+ teacherAdapter,
+ teachersFeatureKey,
+ TeacherState,
+} 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-notification/src/app/teacher.component.ts b/apps/ngrx-notification/src/app/teacher/teacher.component.ts
similarity index 60%
rename from apps/ngrx-notification/src/app/teacher.component.ts
rename to apps/ngrx-notification/src/app/teacher/teacher.component.ts
index 7344f80..63e8122 100644
--- a/apps/ngrx-notification/src/app/teacher.component.ts
+++ b/apps/ngrx-notification/src/app/teacher/teacher.component.ts
@@ -1,6 +1,8 @@
+/* eslint-disable @angular-eslint/component-selector */
import { AsyncPipe, NgFor } from '@angular/common';
import { Component } from '@angular/core';
-import { TeacherStore } from './data-access/teacher.store';
+import { Store } from '@ngrx/store';
+import { TeacherSelectors } from './store/teacher.selectors';
@Component({
standalone: true,
@@ -9,7 +11,7 @@ import { TeacherStore } from './data-access/teacher.store';
template: `
TEACHERS
- {{ teacher.firstname }}
+ {{ teacher.firstname }} {{ teacher.lastname }} - {{ teacher.version }}
`,
styles: [
@@ -25,7 +27,7 @@ import { TeacherStore } from './data-access/teacher.store';
],
})
export class TeacherComponent {
- teacher$ = this.teacherStore.teachers$;
+ teacher$ = this.store.select(TeacherSelectors.selectTeachers);
- constructor(private teacherStore: TeacherStore) {}
+ constructor(private store: Store) {}
}
diff --git a/apps/ngrx-notification/src/main.ts b/apps/ngrx-notification/src/main.ts
index cdabf7b..2192c0b 100644
--- a/apps/ngrx-notification/src/main.ts
+++ b/apps/ngrx-notification/src/main.ts
@@ -1,22 +1,44 @@
-import { PushService } from '@angular-challenges/ngrx-notification/backend';
+import { FakeBackendService } from '@angular-challenges/ngrx-notification/backend';
import { APP_INITIALIZER, enableProdMode, inject } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
+import { provideRouter } from '@angular/router';
+import { provideEffects } from '@ngrx/effects';
+import { provideStore } from '@ngrx/store';
import { AppComponent } from './app/app.component';
import { NotificationService } from './app/data-access/notification.service';
+import { ROUTES } from './app/routes';
+import { StudentEffects } from './app/student/store/student.effects';
+import {
+ studentReducer,
+ studentsFeatureKey,
+} from './app/student/store/student.reducer';
+import { TeacherEffects } from './app/teacher/store/teacher.effects';
+import {
+ teacherReducer,
+ teachersFeatureKey,
+} from './app/teacher/store/teacher.reducer';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
+const REDUCERS = {
+ [teachersFeatureKey]: teacherReducer,
+ [studentsFeatureKey]: studentReducer,
+};
+
bootstrapApplication(AppComponent, {
providers: [
+ provideStore(REDUCERS),
+ provideEffects([TeacherEffects, StudentEffects]),
+ provideRouter(ROUTES),
{
provide: APP_INITIALIZER,
multi: true,
useFactory: () => {
- const service = inject(PushService);
- return () => service.init();
+ const service = inject(FakeBackendService);
+ return () => service.start();
},
},
{
diff --git a/apps/ngrx-notification/tsconfig.editor.json b/apps/ngrx-notification/tsconfig.editor.json
index 7e16fb8..d6ff20e 100644
--- a/apps/ngrx-notification/tsconfig.editor.json
+++ b/apps/ngrx-notification/tsconfig.editor.json
@@ -2,7 +2,7 @@
"extends": "./tsconfig.json",
"include": [
"**/*.ts",
- "../../libs/ngrx-notification/backend/src/lib/push.service.ts"
+ "../../libs/ngrx-notification/backend/src/lib/fake-backend.service.ts"
],
"compilerOptions": {
"types": []
diff --git a/libs/ngrx-notification/backend/src/index.ts b/libs/ngrx-notification/backend/src/index.ts
index bf72113..b61dc61 100644
--- a/libs/ngrx-notification/backend/src/index.ts
+++ b/libs/ngrx-notification/backend/src/index.ts
@@ -1 +1,2 @@
+export * from './lib/fake-backend.service';
export * from './lib/push.service';
diff --git a/libs/ngrx-notification/backend/src/lib/fake-backend.service.ts b/libs/ngrx-notification/backend/src/lib/fake-backend.service.ts
new file mode 100644
index 0000000..639c856
--- /dev/null
+++ b/libs/ngrx-notification/backend/src/lib/fake-backend.service.ts
@@ -0,0 +1,105 @@
+import {
+ randSchool,
+ randStudent,
+ randTeacher,
+} from '@angular-challenges/ngrx-notification/model';
+import { inject, Injectable } from '@angular/core';
+import { randCompanyName, randFirstName } from '@ngneat/falso';
+import { concatLatestFrom } from '@ngrx/effects';
+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$;
+ getAllStchools = () => 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/ngrx-notification/backend/src/lib/fake-db.service.ts b/libs/ngrx-notification/backend/src/lib/fake-db.service.ts
new file mode 100644
index 0000000..689f1de
--- /dev/null
+++ b/libs/ngrx-notification/backend/src/lib/fake-db.service.ts
@@ -0,0 +1,67 @@
+import {
+ School,
+ Student,
+ Teacher,
+} from '@angular-challenges/ngrx-notification/model';
+import { Injectable } from '@angular/core';
+import { randNumber } from '@ngneat/falso';
+import { ComponentStore } from '@ngrx/component-store';
+
+@Injectable({ providedIn: 'root' })
+export class FakeDBService extends ComponentStore<{
+ teachers: Teacher[];
+ students: Student[];
+ schools: School[];
+}> {
+ 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) => ({
+ ...state,
+ teachers: [...state.teachers, teacher],
+ }));
+
+ updateTeacher = this.updater((state, teacher: Teacher) => ({
+ ...state,
+ teachers: state.teachers.map((t) => (t.id === teacher.id ? teacher : t)),
+ }));
+
+ addStudent = this.updater((state, student: Student) => ({
+ ...state,
+ students: [...state.students, student],
+ }));
+
+ updateSudent = this.updater((state, student: Student) => ({
+ ...state,
+ students: state.students.map((t) => (t.id === student.id ? student : t)),
+ }));
+
+ 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)),
+ }));
+}
diff --git a/libs/ngrx-notification/backend/src/lib/push.service.ts b/libs/ngrx-notification/backend/src/lib/push.service.ts
index c1fda14..5369003 100644
--- a/libs/ngrx-notification/backend/src/lib/push.service.ts
+++ b/libs/ngrx-notification/backend/src/lib/push.service.ts
@@ -1,10 +1,6 @@
-import {
- Push,
- randStudent,
- randTeacher,
-} from '@angular-challenges/ngrx-notification/model';
+import { Push } from '@angular-challenges/ngrx-notification/model';
import { Injectable } from '@angular/core';
-import { BehaviorSubject, tap, timer } from 'rxjs';
+import { BehaviorSubject } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class PushService {
@@ -13,20 +9,7 @@ export class PushService {
);
notification$ = this.notificationSubject.asObservable();
- init() {
- this.startTeacherNotification();
- this.startStudentNotification();
- }
-
- private startTeacherNotification() {
- timer(0, 4000)
- .pipe(tap(() => this.notificationSubject.next(randTeacher())))
- .subscribe();
- }
-
- private startStudentNotification() {
- timer(1000, 3000)
- .pipe(tap(() => this.notificationSubject.next(randStudent())))
- .subscribe();
+ pushData(data: Push) {
+ this.notificationSubject.next(data);
}
}
diff --git a/libs/ngrx-notification/model/src/index.ts b/libs/ngrx-notification/model/src/index.ts
index d81af44..d866f8a 100644
--- a/libs/ngrx-notification/model/src/index.ts
+++ b/libs/ngrx-notification/model/src/index.ts
@@ -1,3 +1,4 @@
export * from './lib/push.model';
+export * from './lib/school.model';
export * from './lib/student.model';
export * from './lib/teacher.model';
diff --git a/libs/ngrx-notification/model/src/lib/push.model.ts b/libs/ngrx-notification/model/src/lib/push.model.ts
index a020110..5f1d5f2 100644
--- a/libs/ngrx-notification/model/src/lib/push.model.ts
+++ b/libs/ngrx-notification/model/src/lib/push.model.ts
@@ -1,4 +1,4 @@
-export type PushType = 'teacher' | 'student';
+export type PushType = 'teacher' | 'student' | 'school';
export interface Push {
type: PushType;
diff --git a/libs/ngrx-notification/model/src/lib/school.model.ts b/libs/ngrx-notification/model/src/lib/school.model.ts
new file mode 100644
index 0000000..fd9a6ff
--- /dev/null
+++ b/libs/ngrx-notification/model/src/lib/school.model.ts
@@ -0,0 +1,21 @@
+import { incrementalNumber, randCompanyName } from '@ngneat/falso';
+import { Push } from './push.model';
+
+export interface School extends Push {
+ id: number;
+ name: string;
+ version: number;
+}
+
+const schoolTeacher = incrementalNumber();
+
+export const randSchool = (): School => ({
+ id: schoolTeacher(),
+ name: randCompanyName(),
+ version: 0,
+ type: 'school',
+});
+
+export const isSchool = (notif: Push): notif is School => {
+ return notif.type === 'school';
+};
diff --git a/libs/ngrx-notification/model/src/lib/student.model.ts b/libs/ngrx-notification/model/src/lib/student.model.ts
index 03a3b08..6360b93 100644
--- a/libs/ngrx-notification/model/src/lib/student.model.ts
+++ b/libs/ngrx-notification/model/src/lib/student.model.ts
@@ -1,16 +1,11 @@
-import {
- incrementalNumber,
- randFirstName,
- randLastName,
- randWord,
-} from '@ngneat/falso';
+import { incrementalNumber, randFirstName, randLastName } from '@ngneat/falso';
import { Push } from './push.model';
export interface Student extends Push {
id: number;
firstname: string;
lastname: string;
- school: string;
+ version: number;
}
const factoryStudent = incrementalNumber();
@@ -19,7 +14,7 @@ export const randStudent = (): Student => ({
id: factoryStudent(),
firstname: randFirstName(),
lastname: randLastName(),
- school: randWord(),
+ version: 0,
type: 'student',
});
diff --git a/libs/ngrx-notification/model/src/lib/teacher.model.ts b/libs/ngrx-notification/model/src/lib/teacher.model.ts
index 3fd5707..f7b1ad6 100644
--- a/libs/ngrx-notification/model/src/lib/teacher.model.ts
+++ b/libs/ngrx-notification/model/src/lib/teacher.model.ts
@@ -1,25 +1,11 @@
-import {
- incrementalNumber,
- rand,
- randFirstName,
- randLastName,
-} from '@ngneat/falso';
+import { incrementalNumber, randFirstName, randLastName } from '@ngneat/falso';
import { Push } from './push.model';
-export const subject = [
- 'Sciences',
- 'History',
- 'English',
- 'Maths',
- 'Sport',
-] as const;
-export type Subject = typeof subject[number];
-
export interface Teacher extends Push {
id: number;
firstname: string;
lastname: string;
- subject: Subject;
+ version: number;
}
const factoryTeacher = incrementalNumber();
@@ -28,7 +14,7 @@ export const randTeacher = (): Teacher => ({
id: factoryTeacher(),
firstname: randFirstName(),
lastname: randLastName(),
- subject: rand(subject),
+ version: 0,
type: 'teacher',
});
diff --git a/package-lock.json b/package-lock.json
index b88afd5..e0108ae 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -24,6 +24,7 @@
"@ngneat/falso": "^6.1.0",
"@ngrx/component-store": "^14.3.2",
"@ngrx/effects": "^14.3.2",
+ "@ngrx/entity": "^14.3.2",
"@ngrx/router-store": "^14.3.2",
"@ngrx/store": "^14.3.2",
"@nrwl/angular": "15.0.7",
@@ -42,6 +43,7 @@
"@angular/language-service": "~14.2.0",
"@commitlint/cli": "^17.2.0",
"@commitlint/config-conventional": "^17.2.0",
+ "@ngrx/schematics": "^14.3.2",
"@nrwl/cli": "15.0.7",
"@nrwl/cypress": "15.0.7",
"@nrwl/eslint-plugin-nx": "15.0.7",
@@ -4717,6 +4719,19 @@
"rxjs": "^6.5.3 || ^7.5.0"
}
},
+ "node_modules/@ngrx/entity": {
+ "version": "14.3.2",
+ "resolved": "https://registry.npmjs.org/@ngrx/entity/-/entity-14.3.2.tgz",
+ "integrity": "sha512-Uyb36oVEiTbBJcb6TJ3OTseJdeamNKSxkvqw/uLHt+My87QaRaTEQceDWCsVCBEO4Q4Vgf2g0vbdPZdtGUZcbg==",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "peerDependencies": {
+ "@angular/core": "^14.0.0",
+ "@ngrx/store": "14.3.2",
+ "rxjs": "^6.5.3 || ^7.5.0"
+ }
+ },
"node_modules/@ngrx/router-store": {
"version": "14.3.2",
"resolved": "https://registry.npmjs.org/@ngrx/router-store/-/router-store-14.3.2.tgz",
@@ -4732,6 +4747,12 @@
"rxjs": "^6.5.3 || ^7.5.0"
}
},
+ "node_modules/@ngrx/schematics": {
+ "version": "14.3.2",
+ "resolved": "https://registry.npmjs.org/@ngrx/schematics/-/schematics-14.3.2.tgz",
+ "integrity": "sha512-KoyAao37bmkNuu1wVW21q5Q2VnaHrd46KAlbGHDS8DjWeaL9zrIPNtH8Cqg3Qwm1cCo63qQVqhbO7fCjWl6q5Q==",
+ "dev": true
+ },
"node_modules/@ngrx/store": {
"version": "14.3.2",
"resolved": "https://registry.npmjs.org/@ngrx/store/-/store-14.3.2.tgz",
@@ -23219,6 +23240,14 @@
"tslib": "^2.0.0"
}
},
+ "@ngrx/entity": {
+ "version": "14.3.2",
+ "resolved": "https://registry.npmjs.org/@ngrx/entity/-/entity-14.3.2.tgz",
+ "integrity": "sha512-Uyb36oVEiTbBJcb6TJ3OTseJdeamNKSxkvqw/uLHt+My87QaRaTEQceDWCsVCBEO4Q4Vgf2g0vbdPZdtGUZcbg==",
+ "requires": {
+ "tslib": "^2.0.0"
+ }
+ },
"@ngrx/router-store": {
"version": "14.3.2",
"resolved": "https://registry.npmjs.org/@ngrx/router-store/-/router-store-14.3.2.tgz",
@@ -23227,6 +23256,12 @@
"tslib": "^2.0.0"
}
},
+ "@ngrx/schematics": {
+ "version": "14.3.2",
+ "resolved": "https://registry.npmjs.org/@ngrx/schematics/-/schematics-14.3.2.tgz",
+ "integrity": "sha512-KoyAao37bmkNuu1wVW21q5Q2VnaHrd46KAlbGHDS8DjWeaL9zrIPNtH8Cqg3Qwm1cCo63qQVqhbO7fCjWl6q5Q==",
+ "dev": true
+ },
"@ngrx/store": {
"version": "14.3.2",
"resolved": "https://registry.npmjs.org/@ngrx/store/-/store-14.3.2.tgz",
diff --git a/package.json b/package.json
index 5a6a519..6d71edb 100644
--- a/package.json
+++ b/package.json
@@ -26,6 +26,7 @@
"@ngneat/falso": "^6.1.0",
"@ngrx/component-store": "^14.3.2",
"@ngrx/effects": "^14.3.2",
+ "@ngrx/entity": "^14.3.2",
"@ngrx/router-store": "^14.3.2",
"@ngrx/store": "^14.3.2",
"@nrwl/angular": "15.0.7",
@@ -44,6 +45,7 @@
"@angular/language-service": "~14.2.0",
"@commitlint/cli": "^17.2.0",
"@commitlint/config-conventional": "^17.2.0",
+ "@ngrx/schematics": "^14.3.2",
"@nrwl/cli": "15.0.7",
"@nrwl/cypress": "15.0.7",
"@nrwl/eslint-plugin-nx": "15.0.7",