From 175b7cf65013e6bad70548a3dc20d973d5bfdf8b Mon Sep 17 00:00:00 2001 From: Luka Date: Thu, 21 May 2026 00:03:30 +0400 Subject: [PATCH 1/2] feat(projection): refactor card component using slots --- .../student-card/student-card.component.ts | 33 +++++++++++++++++-- .../teacher-card/teacher-card.component.ts | 31 +++++++++++++---- .../src/app/ui/card/card.component.ts | 33 +++---------------- 3 files changed, 59 insertions(+), 38 deletions(-) diff --git a/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts b/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts index bdfa4abd4..d0b1887d7 100644 --- a/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts +++ b/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts @@ -1,10 +1,14 @@ +import { NgOptimizedImage } from '@angular/common'; import { ChangeDetectionStrategy, Component, inject, OnInit, } from '@angular/core'; -import { FakeHttpService } from '../../data-access/fake-http.service'; +import { + FakeHttpService, + randStudent, +} from '../../data-access/fake-http.service'; import { StudentStore } from '../../data-access/student.store'; import { CardType } from '../../model/card.model'; import { CardComponent } from '../../ui/card/card.component'; @@ -15,7 +19,24 @@ import { CardComponent } from '../../ui/card/card.component'; + customClass="bg-light-green"> +
+ Students list view banner +
+ +
+ +
+
`, styles: [ ` @@ -24,10 +45,12 @@ import { CardComponent } from '../../ui/card/card.component'; } `, ], - imports: [CardComponent], + imports: [CardComponent, NgOptimizedImage], changeDetection: ChangeDetectionStrategy.OnPush, }) export class StudentCardComponent implements OnInit { + private readonly studentStore = inject(StudentStore); + private http = inject(FakeHttpService); private store = inject(StudentStore); @@ -37,4 +60,8 @@ export class StudentCardComponent implements OnInit { ngOnInit(): void { this.http.fetchStudents$.subscribe((s) => this.store.addAll(s)); } + + addNew(): void { + this.studentStore.addOne(randStudent()); + } } diff --git a/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts b/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts index adf0ad3c1..13aa5a8fd 100644 --- a/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts +++ b/apps/angular/1-projection/src/app/component/teacher-card/teacher-card.component.ts @@ -1,5 +1,9 @@ +import { NgOptimizedImage } from '@angular/common'; import { Component, inject, OnInit } from '@angular/core'; -import { FakeHttpService } from '../../data-access/fake-http.service'; +import { + FakeHttpService, + randTeacher, +} from '../../data-access/fake-http.service'; import { TeacherStore } from '../../data-access/teacher.store'; import { CardType } from '../../model/card.model'; import { CardComponent } from '../../ui/card/card.component'; @@ -7,10 +11,19 @@ import { CardComponent } from '../../ui/card/card.component'; @Component({ selector: 'app-teacher-card', template: ` - + +
+ +
+ +
+ +
+
`, styles: [ ` @@ -19,9 +32,11 @@ import { CardComponent } from '../../ui/card/card.component'; } `, ], - imports: [CardComponent], + imports: [CardComponent, NgOptimizedImage], }) export class TeacherCardComponent implements OnInit { + private readonly teacherStore = inject(TeacherStore); + private http = inject(FakeHttpService); private store = inject(TeacherStore); @@ -31,4 +46,8 @@ export class TeacherCardComponent implements OnInit { ngOnInit(): void { this.http.fetchTeachers$.subscribe((t) => this.store.addAll(t)); } + + addNew(): void { + this.teacherStore.addOne(randTeacher()); + } } diff --git a/apps/angular/1-projection/src/app/ui/card/card.component.ts b/apps/angular/1-projection/src/app/ui/card/card.component.ts index 166d9c49a..6a56f91f9 100644 --- a/apps/angular/1-projection/src/app/ui/card/card.component.ts +++ b/apps/angular/1-projection/src/app/ui/card/card.component.ts @@ -1,8 +1,4 @@ -import { NgOptimizedImage } from '@angular/common'; -import { Component, inject, input } from '@angular/core'; -import { randStudent, randTeacher } from '../../data-access/fake-http.service'; -import { StudentStore } from '../../data-access/student.store'; -import { TeacherStore } from '../../data-access/teacher.store'; +import { Component, input } from '@angular/core'; import { CardType } from '../../model/card.model'; import { ListItemComponent } from '../list-item/list-item.component'; @@ -12,12 +8,7 @@ import { ListItemComponent } from '../list-item/list-item.component';
- @if (type() === CardType.TEACHER) { - - } - @if (type() === CardType.STUDENT) { - - } +
@for (item of list(); track item) { @@ -28,31 +19,15 @@ import { ListItemComponent } from '../list-item/list-item.component'; }
- +
`, - imports: [ListItemComponent, NgOptimizedImage], + imports: [ListItemComponent], }) export class CardComponent { - private teacherStore = inject(TeacherStore); - private studentStore = inject(StudentStore); - readonly list = input(null); readonly type = input.required(); readonly customClass = input(''); CardType = CardType; - - addNewItem() { - const type = this.type(); - if (type === CardType.TEACHER) { - this.teacherStore.addOne(randTeacher()); - } else if (type === CardType.STUDENT) { - this.studentStore.addOne(randStudent()); - } - } } From e6719593a26f47542ccc306f32422e47ef149cf1 Mon Sep 17 00:00:00 2001 From: Luka Date: Thu, 21 May 2026 15:24:50 +0400 Subject: [PATCH 2/2] feat(projection): refactor card component using slots --- .../city-card/city-card.component.ts | 62 +++++++++++++++++-- .../student-card/student-card.component.ts | 24 ++++--- .../teacher-card/teacher-card.component.ts | 21 +++++-- .../src/app/data-access/city.store.ts | 2 +- .../src/app/ui/card/card.component.ts | 20 +++--- .../app/ui/list-item/list-item.component.ts | 19 +----- 6 files changed, 106 insertions(+), 42 deletions(-) diff --git a/apps/angular/1-projection/src/app/component/city-card/city-card.component.ts b/apps/angular/1-projection/src/app/component/city-card/city-card.component.ts index 8895c8c84..912889f42 100644 --- a/apps/angular/1-projection/src/app/component/city-card/city-card.component.ts +++ b/apps/angular/1-projection/src/app/component/city-card/city-card.component.ts @@ -1,9 +1,63 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { NgOptimizedImage } from '@angular/common'; +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { CityStore } from '../../data-access/city.store'; +import { + FakeHttpService, + randomCity, +} from '../../data-access/fake-http.service'; +import { CardType } from '../../model/card.model'; +import { CardComponent } from '../../ui/card/card.component'; +import { ListItemComponent } from '../../ui/list-item/list-item.component'; @Component({ selector: 'app-city-card', - template: 'TODO City', - imports: [], + template: ` + +
+ Cities list view banner +
+ + + + + +
+ +
+
+ `, + imports: [CardComponent, NgOptimizedImage, ListItemComponent], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class CityCardComponent {} +export class CityCardComponent { + readonly cityStore = inject(CityStore); + readonly http = inject(FakeHttpService); + + cardType = CardType.CITY; + readonly cities = this.cityStore.cities; + + ngOnInit(): void { + this.http.fetchCities$.subscribe((c) => this.cityStore.addAll(c)); + } + + addNew(): void { + this.cityStore.addOne(randomCity()); + } + + deleteSingle(id: number) { + this.cityStore.deleteOne(id); + } +} diff --git a/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts b/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts index d0b1887d7..19dc123c2 100644 --- a/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts +++ b/apps/angular/1-projection/src/app/component/student-card/student-card.component.ts @@ -12,14 +12,12 @@ import { import { StudentStore } from '../../data-access/student.store'; import { CardType } from '../../model/card.model'; import { CardComponent } from '../../ui/card/card.component'; +import { ListItemComponent } from '../../ui/list-item/list-item.component'; @Component({ selector: 'app-student-card', template: ` - +
+ + + +
@@ -21,19 +19,8 @@ import { CardType } from '../../model/card.model'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class ListItemComponent { - private teacherStore = inject(TeacherStore); - private studentStore = inject(StudentStore); - readonly id = input.required(); readonly name = input.required(); readonly type = input.required(); - - delete(id: number) { - const type = this.type(); - if (type === CardType.TEACHER) { - this.teacherStore.deleteOne(id); - } else if (type === CardType.STUDENT) { - this.studentStore.deleteOne(id); - } - } + readonly emitDelete = output(); }