All files / app/shared/components/article-moderation-panel article-moderation-panel.component.ts

100% Statements 45/45
75% Branches 3/4
100% Functions 13/13
100% Lines 40/40

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 956x   6x                     6x 6x 6x 6x                 6x 53x 53x 53x 53x   53x 53x   53x 55x 55x     53x 53x     55x     53x 53x   55x 55x 55x     2x       9x       2x       2x       13x 13x   13x 13x   13x         9x 9x 9x 9x     4x 4x 4x          
import { ArticleService } from '../../../services/articles/article.service';
import { VersionForModeration } from '../../models/version-for-moderation.model';
import {
    ChangeDetectionStrategy,
    Component,
    DestroyRef,
    computed,
    effect,
    inject,
    input,
    output,
    signal,
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { LoggerService, NotificationService } from '@drevo-web/core';
import { APPROVAL_CLASS, APPROVAL_TITLES, ApprovalStatus, ModerationResult } from '@drevo-web/shared';
import { ButtonComponent, FormatDatePipe, StatusIconComponent, TextInputComponent } from '@drevo-web/ui';
 
@Component({
    selector: 'app-article-moderation-panel',
    imports: [ButtonComponent, StatusIconComponent, TextInputComponent, FormatDatePipe],
    templateUrl: './article-moderation-panel.component.html',
    styleUrl: './article-moderation-panel.component.scss',
    changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ArticleModerationPanelComponent {
    private readonly articleService = inject(ArticleService);
    private readonly destroyRef = inject(DestroyRef);
    private readonly logger = inject(LoggerService).withContext('ArticleModerationPanelComponent');
    private readonly notification = inject(NotificationService);
 
    readonly version = input.required<VersionForModeration>();
    readonly moderated = output<ModerationResult>();
 
    readonly statusText = computed(() => {
        const status = this.version().approved;
        return APPROVAL_TITLES[APPROVAL_CLASS[status]];
    });
 
    private readonly _comment = signal('');
    readonly comment = this._comment.asReadonly();
 
    constructor() {
        effect(() => this._comment.set(this.version().comment ?? ''));
    }
 
    private readonly _isLoading = signal(false);
    readonly isLoading = this._isLoading.asReadonly();
 
    readonly isApproved = computed(() => this.version().approved === ApprovalStatus.Approved);
    readonly isPending = computed(() => this.version().approved === ApprovalStatus.Pending);
    readonly isRejected = computed(() => this.version().approved === ApprovalStatus.Rejected);
 
    onCommentChange(value: string): void {
        this._comment.set(value);
    }
 
    approve(): void {
        this.moderate(ApprovalStatus.Approved, 'Версия одобрена');
    }
 
    sendToReview(): void {
        this.moderate(ApprovalStatus.Pending, 'Версия отправлена на проверку');
    }
 
    reject(): void {
        this.moderate(ApprovalStatus.Rejected, 'Версия отклонена');
    }
 
    private moderate(approved: ApprovalStatus, successMessage: string): void {
        const versionId = this.version().versionId;
        const comment = this._comment();
 
        this._isLoading.set(true);
        this.logger.info('Moderation: submitting', { versionId, approved, comment });
 
        this.articleService
            .moderateVersion(versionId, approved, comment)
            .pipe(takeUntilDestroyed(this.destroyRef))
            .subscribe({
                next: result => {
                    this._isLoading.set(false);
                    this.notification.success(successMessage);
                    this.logger.info('Moderation: success', { versionId, approved });
                    this.moderated.emit(result);
                },
                error: err => {
                    this._isLoading.set(false);
                    this.notification.error('Не удалось выполнить модерацию');
                    this.logger.error('Moderation: failed', err);
                },
            });
    }
}