refactor: notification

This commit is contained in:
thomas
2024-05-13 16:24:11 +02:00
parent fbb9e3eccf
commit 678dd77030
37 changed files with 41 additions and 41 deletions

View File

@@ -0,0 +1,36 @@
{
"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": {}
}
]
}

View File

@@ -0,0 +1,7 @@
# 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.

View File

@@ -0,0 +1,23 @@
/* eslint-disable */
export default {
displayName: 'power-of-effect-backend',
preset: '../../../jest.preset.js',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
globals: {},
coverageDirectory: '../../../coverage/libs/power-of-effect/backend',
transform: {
'^.+\\.(ts|mjs|js|html)$': [
'jest-preset-angular',
{
tsconfig: '<rootDir>/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',
],
};

View File

@@ -0,0 +1,20 @@
{
"name": "power-of-effect-backend",
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
"projectType": "library",
"sourceRoot": "libs/power-of-effect/backend/src",
"prefix": "lib",
"targets": {
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "libs/power-of-effect/backend/jest.config.ts"
}
},
"lint": {
"executor": "@nx/eslint:lint"
}
},
"tags": []
}

View File

@@ -0,0 +1,2 @@
export * from './lib/fake-backend.service';
export * from './lib/push.service';

View File

@@ -0,0 +1,105 @@
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/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$;
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();
}
}

View File

@@ -0,0 +1,81 @@
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<AppState> {
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)),
}),
);
}

View File

@@ -0,0 +1,15 @@
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<Push | undefined>(
undefined,
);
notification$ = this.notificationSubject.asObservable();
pushData(data: Push) {
this.notificationSubject.next(data);
}
}

View File

@@ -0,0 +1 @@
import 'jest-preset-angular/setup-jest';

View File

@@ -0,0 +1,28 @@
{
"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
}
}

View File

@@ -0,0 +1,17 @@
{
"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"]
}

View File

@@ -0,0 +1,10 @@
{
"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"]
}