feat(challenge 7): begin ngrx notification work

This commit is contained in:
thomas laforge
2022-11-22 22:25:27 +01:00
parent d774abf3b1
commit cc1c6e8b26
25 changed files with 596 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
import { Component } from '@angular/core';
import { StudentComponent } from './student.component';
import { TeacherComponent } from './teacher.component';
@Component({
standalone: true,
imports: [TeacherComponent, StudentComponent],
selector: 'app-root',
template: `
<teacher></teacher>
<student></student>
`,
styles: [
`
:host {
display: flex;
gap: 20px;
}
`,
],
})
export class AppComponent {}

View File

@@ -0,0 +1,27 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject, tap, timer } from 'rxjs';
import { randStudent } from '../model/student.model';
import { randTeacher } from '../model/teacher.model';
@Injectable({ providedIn: 'root' })
export class PushService {
private notificationSubject = new BehaviorSubject<any>(undefined);
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();
}
}

View File

@@ -0,0 +1,31 @@
import { Injectable } from '@angular/core';
import { filter } from 'rxjs';
import { PushService } from '../backend/push.service';
import { Push } from '../model/push.model';
import { isStudent } from '../model/student.model';
import { isTeacher } from '../model/teacher.model';
import { StudentStore } from './student.store';
import { TeacherStore } from './teacher.store';
@Injectable({ providedIn: 'root' })
export class NotificationService {
constructor(
private pushService: PushService,
private teacherStore: TeacherStore,
private studentStore: StudentStore
) {}
init() {
this.pushService.notification$
.pipe(filter(Boolean))
.subscribe((notification: Push) => {
console.log(notification);
if (isTeacher(notification)) {
this.teacherStore.addOne(notification);
}
if (isStudent(notification)) {
this.studentStore.addOne(notification);
}
});
}
}

View File

@@ -0,0 +1,23 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { Student } from '../model/student.model';
@Injectable({
providedIn: 'root',
})
export class StudentStore {
private students = new BehaviorSubject<Student[]>([]);
students$ = this.students.asObservable();
addAll(students: Student[]) {
this.students.next(students);
}
addOne(student: Student) {
this.students.next([...this.students.value, student]);
}
deleteOne(id: number) {
this.students.next(this.students.value.filter((s) => s.id !== id));
}
}

View File

@@ -0,0 +1,23 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { Teacher } from '../model/teacher.model';
@Injectable({
providedIn: 'root',
})
export class TeacherStore {
private teachers = new BehaviorSubject<Teacher[]>([]);
teachers$ = this.teachers.asObservable();
addAll(teachers: Teacher[]) {
this.teachers.next(teachers);
}
addOne(teacher: Teacher) {
this.teachers.next([...this.teachers.value, teacher]);
}
deleteOne(id: number) {
this.teachers.next(this.teachers.value.filter((t) => t.id !== id));
}
}

View File

@@ -0,0 +1,5 @@
export type PushType = 'teacher' | 'student';
export interface Push {
type: PushType;
}

View File

@@ -0,0 +1,28 @@
import {
incrementalNumber,
randFirstName,
randLastName,
randWord,
} from '@ngneat/falso';
import { Push } from './push.model';
export interface Student extends Push {
id: number;
firstname: string;
lastname: string;
school: string;
}
const factoryStudent = incrementalNumber();
export const randStudent = (): Student => ({
id: factoryStudent(),
firstname: randFirstName(),
lastname: randLastName(),
school: randWord(),
type: 'student',
});
export const isStudent = (notif: Push): notif is Student => {
return notif.type === 'student';
};

View File

@@ -0,0 +1,37 @@
import {
incrementalNumber,
rand,
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;
}
const factoryTeacher = incrementalNumber();
export const randTeacher = () => ({
id: factoryTeacher(),
firstname: randFirstName(),
lastname: randLastName(),
subject: rand(subject),
type: 'teacher',
});
export const isTeacher = (notif: Push): notif is Teacher => {
return notif.type === 'teacher';
};

View File

@@ -0,0 +1,32 @@
/* eslint-disable @angular-eslint/component-selector */
import { AsyncPipe, NgFor } from '@angular/common';
import { Component } from '@angular/core';
import { StudentStore } from './data-access/student.store';
@Component({
standalone: true,
imports: [NgFor, AsyncPipe],
selector: 'student',
template: `
<h3>STUDENTS</h3>
<div *ngFor="let student of students$ | async">
{{ student.firstname }}
</div>
`,
styles: [
`
:host {
display: block;
width: fit-content;
height: fit-content;
border: 1px solid red;
padding: 4px;
}
`,
],
})
export class StudentComponent {
students$ = this.studentStore.students$;
constructor(private studentStore: StudentStore) {}
}

View File

@@ -0,0 +1,31 @@
import { AsyncPipe, NgFor } from '@angular/common';
import { Component } from '@angular/core';
import { TeacherStore } from './data-access/teacher.store';
@Component({
standalone: true,
imports: [NgFor, AsyncPipe],
selector: 'teacher',
template: `
<h3>TEACHERS</h3>
<div *ngFor="let teacher of teacher$ | async">
{{ teacher.firstname }}
</div>
`,
styles: [
`
:host {
display: block;
width: fit-content;
height: fit-content;
border: 1px solid red;
padding: 4px;
}
`,
],
})
export class TeacherComponent {
teacher$ = this.teacherStore.teachers$;
constructor(private teacherStore: TeacherStore) {}
}