Skip to content

Commit 8afac33

Browse files
committed
add expert id for criterias
1 parent 4caad55 commit 8afac33

4 files changed

Lines changed: 126 additions & 30 deletions

File tree

projects/social_platform/src/app/office/features/project-rating/project-rating.component.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ export class ProjectRatingComponent implements OnDestroy, ControlValueAccessor,
102102

103103
private _disabled = false;
104104

105+
@Input() currentUserId!: number;
106+
105107
/** Сигнал для хранения критериев оценки */
106108
_criteria = signal<ProjectRatingCriterion[]>([]);
107109

projects/social_platform/src/app/office/program/models/project-rating-criterion.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,5 @@ export interface ProjectRatingCriterion {
2525
minValue: number | null;
2626
maxValue: number | null;
2727
value: string | number;
28+
expertId: number;
2829
}

projects/social_platform/src/app/office/program/shared/rating-card/rating-card.component.html

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,12 @@
7676
<app-project-rating
7777
[criteria]="project.criterias"
7878
[formControl]="form"
79-
[disabled]="(projectRated() || projectConfirmed()) && !programDateFinished()"
79+
[currentUserId]="profile().id"
80+
[disabled]="
81+
(projectRated() || projectConfirmed()) &&
82+
project.ratedExperts.includes(profile().id) &&
83+
!programDateFinished()
84+
"
8085
></app-project-rating>
8186
@if (form | controlError: "required"; as error) {
8287
<div class="text-body-10 error">
@@ -95,7 +100,8 @@
95100
[disabled]="isButtonDisabled"
96101
[style.opacity]="buttonOpacity"
97102
[color]="buttonColor"
98-
(click)="canRate ? showConfirmRateModal.set(true) : null"
103+
[title]="buttonTooltip"
104+
(click)="handleRateButtonClick()"
99105
>
100106
{{ rateButtonText }}
101107
</app-button>
@@ -133,7 +139,7 @@
133139
<app-project-rating
134140
[criteria]="project.criterias"
135141
[formControl]="form"
136-
[disabled]="(projectRated() || projectConfirmed()) && !programDateFinished()"
142+
[disabled]="true"
137143
></app-project-rating>
138144
}
139145
</div>

projects/social_platform/src/app/office/program/shared/rating-card/rating-card.component.ts

Lines changed: 114 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,9 @@ import {
55
ChangeDetectorRef,
66
Component,
77
ElementRef,
8-
EventEmitter,
98
Input,
109
OnDestroy,
1110
OnInit,
12-
Output,
1311
signal,
1412
ViewChild,
1513
} from "@angular/core";
@@ -39,7 +37,6 @@ import { TagComponent } from "@ui/components/tag/tag.component";
3937
import { ModalComponent } from "@ui/components/modal/modal.component";
4038
import { ProgramDataService } from "@office/program/services/program-data.service";
4139
import { AuthService } from "@auth/services";
42-
import { User } from "@auth/models/user.model";
4340
import { TruncatePipe } from "projects/core/src/lib/pipes/truncate.pipe";
4441
import { HttpResponse } from "@angular/common/http";
4542

@@ -51,25 +48,14 @@ import { HttpResponse } from "@angular/common/http";
5148
*
5249
* Принимает:
5350
* @Input project: ProjectRate | null - Текущий проект для оценки
54-
* @Input projects: ProjectRate[] | null - Список всех проектов
55-
* @Input currentIndex: number - Индекс текущего проекта в списке
56-
*
57-
* Генерирует:
58-
* @Output onNext: EventEmitter<void> - Событие перехода к следующему проекту
59-
* @Output onPrev: EventEmitter<void> - Событие перехода к предыдущему проекту
60-
*
61-
* Зависимости:
62-
* @param {IndustryService} industryService - Сервис для работы с отраслями
63-
* @param {ProjectRatingService} projectRatingService - Сервис оценки проектов
64-
* @param {BreakpointObserver} breakpointObserver - Для адаптивного дизайна
65-
* @param {ChangeDetectorRef} cdRef - Для ручного обновления представления
6651
*
6752
* Функциональность:
6853
* - Отображение информации о проекте (название, описание, изображения)
6954
* - Форма оценки с различными типами критериев
7055
* - Возможность развернуть/свернуть описание проекта
71-
* - Навигация между проектами
7256
* - Отправка оценки и обработка результата
57+
* - Поддержка переоценки для пользователей, которые уже оценили
58+
* - Блокировка оценки при достижении лимита (только для тех, кто не оценивал)
7359
* - Адаптивный дизайн для мобильных устройств
7460
*
7561
* Состояния:
@@ -79,7 +65,8 @@ import { HttpResponse } from "@angular/common/http";
7965
* @property {Signal<boolean>} descriptionExpandable - Можно ли развернуть описание
8066
* @property {Signal<boolean>} projectRated - Оценен ли проект (временно)
8167
* @property {Signal<boolean>} projectConfirmed - Подтверждена ли оценка окончательно
82-
* @property {Signal<boolean>} confirmLoading - Состояние загрузки при подтверждении
68+
* @property {Signal<boolean>} locallyRatedByCurrentUser - Оценил ли пользователь локально
69+
* @property {Signal<number>} ratedCount - Количество оценок проекта
8370
*/
8471
@Component({
8572
selector: "app-rating-card",
@@ -92,7 +79,6 @@ import { HttpResponse } from "@angular/common/http";
9279
AvatarComponent,
9380
IconComponent,
9481
ButtonComponent,
95-
AvatarComponent,
9682
ParseLinksPipe,
9783
ParseBreaksPipe,
9884
ProjectRatingComponent,
@@ -217,6 +203,9 @@ export class RatingCardComponent implements OnInit, AfterViewInit, OnDestroy {
217203
this.readFullDescription.set(!isExpanded);
218204
}
219205

206+
/**
207+
* Подтверждение оценки проекта
208+
*/
220209
confirmRateProject(): void {
221210
this.form.markAsTouched();
222211
if (this.form.invalid) return;
@@ -246,34 +235,41 @@ export class RatingCardComponent implements OnInit, AfterViewInit, OnDestroy {
246235
project.ratedExperts = [];
247236
}
248237

238+
// Проверяем, первый ли раз пользователь оценивает
249239
if (!project.ratedExperts.includes(profile.id)) {
250240
project.ratedExperts = [...project.ratedExperts, profile.id];
251241
isFirstTimeRating = true;
252242
}
253243
}
254244

245+
// Увеличиваем счетчик только при первой оценке
255246
if (isFirstTimeRating) {
256247
this.ratedCount.update(count => count + 1);
257248
}
258-
this._project.set({ ...project });
259249

250+
this._project.set({ ...project });
260251
this.showConfirmRateModal.set(false);
261252
},
262253
error: err => {
263254
if (err instanceof HttpResponse) {
264255
if (err.status === 400) {
265-
console.log("error of max rated");
266-
console.error("error of max rated");
256+
console.error("Ошибка: достигнут максимальный лимит оценок");
267257
}
268258
}
269259
},
270260
});
271261
}
272262

263+
/**
264+
* Переоценка проекта
265+
* Сбрасываем статусы, но НЕ удаляем пользователя из списка оценивших
266+
* После этого пользователь может заново оценить проект
267+
*/
273268
redoRating(): void {
274269
this.projectRated.set(false);
275270
this.projectConfirmed.set(false);
276-
this.locallyRatedByCurrentUser.set(false);
271+
// locallyRatedByCurrentUser остается true, так как пользователь уже в списке оценивших
272+
// После сброса статусов кнопка станет "оценить проект" и откроет модалку
277273
}
278274

279275
openPresentation(url: string) {
@@ -300,33 +296,73 @@ export class RatingCardComponent implements OnInit, AfterViewInit, OnDestroy {
300296
return isExpertFromBackend || isExpertLocally;
301297
}
302298

299+
/**
300+
* Проверяет, может ли пользователь оценить проект
301+
* Условия:
302+
* 1. Программа не завершена
303+
* 2. Либо лимит не достигнут, либо пользователь уже оценивал (может переоценить)
304+
*/
303305
get canRate(): boolean {
304306
if (this.programDateFinished()) return false;
305307

308+
// Если лимит достигнут, но пользователь уже оценивал - разрешаем переоценку
306309
if (this.isLimitReached && !this.userRatedThisProject) return false;
307310

308311
return true;
309312
}
310313

314+
/**
315+
* Текст кнопки в зависимости от состояния
316+
*/
311317
get rateButtonText(): string {
312-
if (this.projectConfirmed()) return "проект оценен";
313-
if (this.isLimitReached) return "проект оценен";
318+
if (this.programDateFinished()) return "программа завершена";
319+
if (this.projectConfirmed() && this.userRatedThisProject) return "проект оценен";
320+
if (this.isLimitReached && !this.userRatedThisProject) return "лимит оценок достигнут";
314321

315322
return "оценить проект";
316323
}
317324

325+
/**
326+
* Показывать ли форму оценки
327+
*/
318328
get showRatingForm(): boolean {
319329
return !this.projectRated() && this.canEdit;
320330
}
321331

332+
/**
333+
* Показывать ли статус "оценено"
334+
*/
322335
get showRatedStatus(): boolean {
323336
return this.projectRated() || this.projectConfirmed();
324337
}
325338

339+
/**
340+
* Показывать ли кнопку редактирования
341+
* Только если пользователь оценил проект, программа не завершена
342+
*/
326343
get showEditButton(): boolean {
327344
return this.projectConfirmed() && !this.programDateFinished() && this.userRatedThisProject;
328345
}
329346

347+
/**
348+
* Проверяет, можно ли открыть модальное окно оценки
349+
* Модальное окно открывается только для:
350+
* 1. Первой оценки (когда пользователь не оценивал и лимит не превышен)
351+
* 2. Переоценки (когда пользователь нажал кнопку редактирования)
352+
*
353+
* НЕ открывается когда проект уже оценен и пользователь просто кликает на зеленую кнопку
354+
*/
355+
get canOpenModal(): boolean {
356+
// Если проект подтвержден и оценен - НЕ открываем модалку по клику на кнопку
357+
if (this.projectConfirmed() && this.userRatedThisProject) return false;
358+
359+
// В остальных случаях проверяем canRate
360+
return this.canRate;
361+
}
362+
363+
/**
364+
* Проверяет, оценил ли текущий пользователь этот проект
365+
*/
330366
get userRatedThisProject(): boolean {
331367
const profile = this.profile();
332368
const project = this.project;
@@ -339,28 +375,79 @@ export class RatingCardComponent implements OnInit, AfterViewInit, OnDestroy {
339375
);
340376
}
341377

378+
/**
379+
* Должна ли кнопка быть неактивной
380+
*/
342381
get isButtonDisabled(): boolean {
382+
// Если лимит достигнут и пользователь не оценивал - блокируем
343383
if (this.isLimitReached && !this.userRatedThisProject) return true;
344384

345-
if (!this.canRate) return true;
385+
// Если программа завершена - блокируем
386+
if (this.programDateFinished()) return true;
346387

347-
return false;
388+
// В остальных случаях проверяем canRate
389+
return !this.canRate;
348390
}
349391

392+
/**
393+
* Цвет кнопки
394+
*/
350395
get buttonColor(): "green" | "primary" {
351396
if (this.userRatedThisProject) return "green";
352397
return "primary";
353398
}
354399

400+
/**
401+
* Прозрачность кнопки
402+
*/
355403
get buttonOpacity(): string {
356404
return this.isButtonDisabled ? "0.5" : "1";
357405
}
358406

407+
/**
408+
* Проверяет, достигнут ли лимит оценок
409+
*/
359410
get isLimitReached(): boolean {
360411
return !!this.project && this.project.ratedCount >= this.project.maxRates;
361412
}
362413

414+
/**
415+
* Показывать ли состояние "подтверждено"
416+
*/
363417
get showConfirmedState(): boolean {
364-
return (this.projectConfirmed() && !this.canEdit) || this.isLimitReached;
418+
return (
419+
(this.projectConfirmed() && !this.canEdit) ||
420+
(this.isLimitReached && !this.userRatedThisProject)
421+
);
422+
}
423+
424+
/**
425+
* Обработка клика по кнопке оценки
426+
*/
427+
handleRateButtonClick(): void {
428+
// Открываем модальное окно только если можно оценить
429+
if (this.canOpenModal) {
430+
this.showConfirmRateModal.set(true);
431+
}
432+
}
433+
434+
/**
435+
* Дополнительная проверка для визуального состояния кнопки
436+
*/
437+
get buttonTooltip(): string {
438+
if (this.programDateFinished()) return "Программа завершена";
439+
if (this.isLimitReached && !this.userRatedThisProject) {
440+
return "Достигнут максимальный лимит оценок";
441+
}
442+
if (this.userRatedThisProject) return "Нажмите для переоценки";
443+
return "Нажмите для оценки проекта";
444+
}
445+
446+
/**
447+
* Должна ли форма в модалке быть отключена
448+
* Форма отключена для просмотра, пользователь подтверждает без изменений
449+
*/
450+
get isModalFormDisabled(): boolean {
451+
return true; // Всегда disabled в модалке для подтверждения
365452
}
366453
}

0 commit comments

Comments
 (0)