Skip to content

Commit 3389f55

Browse files
committed
refactor(rating-card): extract business logic to RatingCardService
- Create RatingCardService with computed signals and rating flow methods - Move service to services/ folder within rating-card - Replace all getter proxies with protected readonly field aliases - Remove unused fields (_currentIndex, _projects) - Consolidate ExpandService usage across 5 components - Remove dead expand code from CourseInfoComponent - All injects changed to private readonly - Templates no longer access services directly
1 parent d08e5ee commit 3389f55

12 files changed

Lines changed: 366 additions & 430 deletions

File tree

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,9 @@
11
/** @format */
22

3-
import {
4-
AfterViewInit,
5-
ChangeDetectorRef,
6-
Component,
7-
ElementRef,
8-
HostListener,
9-
inject,
10-
OnInit,
11-
ViewChild,
12-
} from "@angular/core";
3+
import { Component, HostListener, inject } from "@angular/core";
134
import { RouterModule } from "@angular/router";
145
import { ParseBreaksPipe, ParseLinksPipe } from "@corelib";
156
import { IconComponent } from "@uilib";
16-
import { expandElement } from "@utils/expand-element";
177
import { CommonModule } from "@angular/common";
188
import { ModalComponent } from "@ui/primitives/modal/modal.component";
199
import { ButtonComponent } from "@ui/primitives";
@@ -27,10 +17,7 @@ import { CourseAboutComponent } from "@ui/widgets/course-about/course-about.comp
2717
selector: "app-detail",
2818
standalone: true,
2919
imports: [
30-
IconComponent,
3120
RouterModule,
32-
ParseBreaksPipe,
33-
ParseLinksPipe,
3421
CommonModule,
3522
SoonCardComponent,
3623
ModalComponent,
@@ -41,38 +28,19 @@ import { CourseAboutComponent } from "@ui/widgets/course-about/course-about.comp
4128
templateUrl: "./info.component.html",
4229
styleUrl: "./info.component.scss",
4330
})
44-
export class CourseInfoComponent implements OnInit, AfterViewInit {
45-
@ViewChild("descEl") descEl?: ElementRef;
46-
31+
export class CourseInfoComponent {
4732
protected appWidth = window.innerWidth;
4833

4934
@HostListener("window:resize")
5035
onResize() {
5136
this.appWidth = window.innerWidth;
5237
}
5338

54-
private readonly cdRef = inject(ChangeDetectorRef);
5539
private readonly courseDetailUIInfoService = inject(CourseDetailUIInfoService);
5640

5741
protected readonly courseStructure = this.courseDetailUIInfoService.courseStructure;
5842
protected readonly courseDetail = this.courseDetailUIInfoService.course;
5943
protected readonly courseModules = this.courseDetailUIInfoService.courseModules;
6044
protected readonly isCompleteModule = this.courseDetailUIInfoService.isCompleteModule;
6145
protected readonly isCourseCompleted = this.courseDetailUIInfoService.isCourseCompleted;
62-
63-
protected descriptionExpandable?: boolean;
64-
protected readFullDescription!: boolean;
65-
66-
ngOnInit(): void {}
67-
68-
ngAfterViewInit(): void {
69-
const descElement = this.descEl?.nativeElement;
70-
this.descriptionExpandable = descElement?.clientHeight < descElement?.scrollHeight;
71-
this.cdRef.detectChanges();
72-
}
73-
74-
onExpandDescription(elem: HTMLElement, expandedClass: string, isExpanded: boolean): void {
75-
expandElement(elem, expandedClass, isExpanded);
76-
this.readFullDescription = !isExpanded;
77-
}
7846
}

projects/social_platform/src/app/ui/pages/feed/open-vacancy/open-vacancy.component.html

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
{{ project.name | truncate: 30 }}
2222
</p>
2323

24-
@if (industryRepository.getOne(project.industry); as industry) {
24+
@if (industryRepositoryGetOne(project.industry); as industry) {
2525
<app-tag class="card__industry" color="complete">
2626
{{ industry.name }}
2727
</app-tag>
@@ -59,7 +59,7 @@ <h3 class="text-body-10 lists__title">
5959
}
6060
</div>
6161
} @if (skillsLength > 8) {
62-
<div class="read-more text-body-10" (click)="readFullSkills = !readFullSkills">
62+
<div class="read-more text-body-10" (click)="toggleSkills()">
6363
{{ readFullSkills ? "cкрыть" : "подробнее" }}
6464
</div>
6565
} }
@@ -73,12 +73,9 @@ <h3 class="text-body-10 lists__title">
7373
#descEl
7474
[innerHTML]="vacancy.description | parseLinks | parseBreaks"
7575
></p>
76-
@if (descriptionExpandable) {
77-
<div
78-
class="read-more text-body-10"
79-
(click)="onExpandDescription(descEl, 'expanded', readFullDescription)"
80-
>
81-
{{ readFullDescription ? "скрыть" : "подробнее" }}
76+
@if (descriptionExpandable()) {
77+
<div class="read-more text-body-10" (click)="onExpandDescription(descEl)">
78+
{{ readFullDescription() ? "скрыть" : "подробнее" }}
8279
</div>
8380
}
8481
</div>

projects/social_platform/src/app/ui/pages/feed/open-vacancy/open-vacancy.component.ts

Lines changed: 25 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
import {
44
AfterViewInit,
55
ChangeDetectionStrategy,
6-
ChangeDetectorRef,
76
Component,
87
ElementRef,
8+
inject,
99
Input,
1010
ViewChild,
1111
} from "@angular/core";
@@ -14,11 +14,11 @@ import { ButtonComponent } from "@ui/primitives";
1414
import { Router, RouterLink } from "@angular/router";
1515
import { TagComponent } from "@ui/primitives/tag/tag.component";
1616
import { Vacancy } from "@domain/vacancy/vacancy.model";
17-
import { expandElement } from "@utils/expand-element";
1817
import { AvatarComponent } from "@ui/primitives/avatar/avatar.component";
1918
import { TruncatePipe, DayjsPipe, ParseBreaksPipe, ParseLinksPipe } from "@corelib";
2019
import { AppRoutes } from "@api/paths/app-routes";
2120
import { IndustryRepositoryPort } from "@domain/industry/ports/industry.repository.port";
21+
import { ExpandService } from "@api/expand/expand.service";
2222

2323
/** Карточка вакансии в ленте с поддержкой разворачивания контента. */
2424
@Component({
@@ -38,48 +38,40 @@ import { IndustryRepositoryPort } from "@domain/industry/ports/industry.reposito
3838
templateUrl: "./open-vacancy.component.html",
3939
styleUrl: "./open-vacancy.component.scss",
4040
changeDetection: ChangeDetectionStrategy.OnPush,
41+
providers: [ExpandService],
4142
})
4243
export class OpenVacancyComponent implements AfterViewInit {
4344
@Input() feedItem!: Vacancy;
44-
protected readonly AppRoutes = AppRoutes;
4545

46-
@ViewChild("skillsEl") skillsEl?: ElementRef;
47-
@ViewChild("descEl") descEl?: ElementRef;
46+
private readonly expandService = inject(ExpandService);
47+
protected readonly AppRoutes = AppRoutes;
48+
private readonly industryRepository = inject(IndustryRepositoryPort);
4849

49-
constructor(
50-
public readonly router: Router,
51-
private readonly cdRef: ChangeDetectorRef,
52-
public readonly industryRepository: IndustryRepositoryPort
53-
) {}
50+
@ViewChild("skillsEl") private skillsEl?: ElementRef;
51+
@ViewChild("descEl") private descEl?: ElementRef;
5452

55-
ngAfterViewInit(): void {
56-
// Проверяем, превышает ли описание доступную высоту
57-
const descElement = this.descEl?.nativeElement;
58-
this.descriptionExpandable = descElement?.clientHeight < descElement?.scrollHeight;
53+
readFullSkills = false;
5954

60-
// Проверяем, превышает ли список навыков доступную высоту
61-
const skillsElement = this.skillsEl?.nativeElement;
62-
this.skillsExpandable = skillsElement?.clientHeight < skillsElement?.scrollHeight;
55+
protected readonly descriptionExpandable = this.expandService.descriptionExpandable;
56+
protected readonly readFullDescription = this.expandService.readFullDescription;
57+
protected readonly industryRepositoryGetOne = (id: number) => this.industryRepository.getOne(id);
6358

64-
// Обновляем UI после изменения флагов
65-
this.cdRef.detectChanges();
59+
ngAfterViewInit(): void {
60+
setTimeout(() => {
61+
this.expandService.checkExpandable("description", true, this.descEl);
62+
});
6663
}
6764

68-
// Флаги для определения возможности развертывания контента
69-
descriptionExpandable!: boolean; // Можно ли развернуть описание
70-
skillsExpandable!: boolean; // Можно ли развернуть список навыков
71-
72-
// Состояние развертывания контента
73-
readFullDescription = false; // Развернуто ли описание
74-
readFullSkills = false; // Развернут ли список навыков
75-
76-
onExpandDescription(elem: HTMLElement, expandedClass: string, isExpanded: boolean): void {
77-
expandElement(elem, expandedClass, isExpanded);
78-
this.readFullDescription = !isExpanded;
65+
protected onExpandDescription(elem: HTMLElement): void {
66+
this.expandService.onExpand(
67+
"description",
68+
elem,
69+
"expanded",
70+
this.expandService.readFullDescription()
71+
);
7972
}
8073

81-
onExpandSkills(elem: HTMLElement, expandedClass: string, isExpanded: boolean): void {
82-
expandElement(elem, expandedClass, isExpanded);
83-
this.readFullSkills = !isExpanded;
74+
protected toggleSkills(): void {
75+
this.readFullSkills = !this.readFullSkills;
8476
}
8577
}

projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/rating-card.component.html

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<p class="text-body-12 card__naming--text">{{ project.name | truncate: 15 }}</p>
1818
</a>
1919

20-
@if (industryRepository.getOne(project.industry); as industry) {
20+
@if (industryRepositoryGetOne(project.industry); as industry) {
2121
<app-tag class="card__industry" color="complete">
2222
{{ industry.name }}
2323
</app-tag>
@@ -49,10 +49,7 @@
4949
<div class="text-body-10 about__text">
5050
<p #descEl [innerHTML]="project.description | parseLinks | parseBreaks"></p>
5151
@if (descriptionExpandable()) {
52-
<div
53-
class="about__read-full text-body-10"
54-
(click)="expandDescription(descEl, 'expanded', readFullDescription())"
55-
>
52+
<div class="about__read-full text-body-10" (click)="onExpandDescription(descEl)">
5653
{{ readFullDescription() ? "скрыть" : "подробнее" }}
5754
</div>
5855
}
@@ -74,36 +71,36 @@
7471
</div>
7572
<app-project-rating
7673
[criteria]="project.criterias"
77-
[formControl]="form"
74+
[formControl]="form()"
7875
[currentUserId]="profile()!.id"
7976
[disabled]="
80-
(projectRated() || projectConfirmed()) && isRatedByCurrentUser && !programDateFinished()
77+
(projectRated() || projectConfirmed()) && isRatedByCurrentUser() && !programDateFinished()
8178
"
8279
></app-project-rating>
83-
@if (form | controlError: "required"; as error) {
80+
@if (form() | controlError: "required"; as error) {
8481
<div class="text-body-10 error">
8582
{{ error }}
8683
</div>
8784
}
8885
</div>
8986

90-
@if (showRatingForm || showRatedStatus || showConfirmedState) {
87+
@if (showRatingForm() || showRatedStatus() || showConfirmedState()) {
9188
<div class="card__rated">
9289
<app-button
9390
style="flex-grow: 1"
9491
customTypographyClass="text-body-12"
9592
size="big"
9693
[loader]="submitLoading() || confirmLoading()"
97-
[disabled]="isButtonDisabled"
98-
[style.opacity]="buttonOpacity"
99-
[color]="buttonColor"
100-
[title]="buttonTooltip"
94+
[disabled]="isButtonDisabled()"
95+
[style.opacity]="buttonOpacity()"
96+
[color]="buttonColor()"
97+
[title]="buttonTooltip()"
10198
(click)="handleRateButtonClick()"
10299
>
103-
{{ rateButtonText }}
100+
{{ rateButtonText() }}
104101
</app-button>
105102

106-
@if (showEditButton) {
103+
@if (showEditButton()) {
107104
<app-button
108105
appearance="outline"
109106
size="small"
@@ -117,10 +114,7 @@
117114
</div>
118115
}
119116

120-
<app-modal
121-
[open]="showConfirmRateModal()"
122-
(openChange)="showConfirmRateModal.set(!showConfirmRateModal())"
123-
>
117+
<app-modal [open]="showConfirmRateModal()" (openChange)="toggleConfirmRateModal()">
124118
<div class="cancel">
125119
<div class="cancel__top">
126120
<p class="cancel__title text-body-14">подтвердите оценку</p>
@@ -135,7 +129,7 @@
135129
@if (showConfirmRateModal()) {
136130
<app-project-rating
137131
[criteria]="project.criterias"
138-
[formControl]="form"
132+
[formControl]="form()"
139133
[disabled]="true"
140134
></app-project-rating>
141135
}
@@ -156,7 +150,7 @@
156150
class="cancel__button"
157151
appearance="outline"
158152
customTypographyClass="text-body-12"
159-
(click)="showConfirmRateModal.set(false)"
153+
(click)="closeConfirmRateModal()"
160154
>
161155
изменить оценку
162156
</app-button>

0 commit comments

Comments
 (0)