@@ -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";
3937import { ModalComponent } from "@ui/components/modal/modal.component" ;
4038import { ProgramDataService } from "@office/program/services/program-data.service" ;
4139import { AuthService } from "@auth/services" ;
42- import { User } from "@auth/models/user.model" ;
4340import { TruncatePipe } from "projects/core/src/lib/pipes/truncate.pipe" ;
4441import { 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