From 18984746f11a4bfe01642c585373d60be4172dcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Mau=C3=9F?= <lukas.mauss@gmx.de> Date: Wed, 3 Feb 2021 17:34:27 +0100 Subject: [PATCH] Add filter by time period to comment list A new button is now displayed in comment list view for creators and participants. A click on the button will open a menu with which the user can select a time period for the displayed comments. Sorting and filtering actions will applied to the selected period. Displaying all existing comments is the default setting. --- .../comment-list/comment-list.component.html | 34 +++++++-- .../comment-list/comment-list.component.scss | 4 ++ .../comment-list/comment-list.component.ts | 70 +++++++++++++++---- 3 files changed, 90 insertions(+), 18 deletions(-) diff --git a/src/app/components/shared/comment-list/comment-list.component.html b/src/app/components/shared/comment-list/comment-list.component.html index 113b01146..f0696d1f3 100644 --- a/src/app/components/shared/comment-list/comment-list.component.html +++ b/src/app/components/shared/comment-list/comment-list.component.html @@ -36,9 +36,9 @@ <div class="button-bar" fxLayoutAlign="center center"> - <div *ngIf="comments && comments.length > 0"> + <div *ngIf="comments && commentsFilteredByTime.length > 0"> <h3 class="counter" - *ngIf="!hideCommentsList">{{comments.length}}</h3> + *ngIf="!hideCommentsList">{{commentsFilteredByTime.length}}</h3> <h3 class="counter-filtered" *ngIf="filteredComments && hideCommentsList">{{filteredComments.length}}</h3> </div> @@ -70,6 +70,16 @@ <mat-icon class="searchBarIcon">filter_list</mat-icon> </button> + <button id="time-button" + mat-icon-button + class="searchBarButton" + aria-labelledby="time_settings" + *ngIf="!searchBox.value && comments && comments.length > 0 && !search" + [matMenuTriggerFor]="timeMenu" + matTooltip="{{ 'comment-list.select-time' | translate }}"> + <mat-icon class="searchBarIcon">access_time</mat-icon> + </button> + <button id="pause-comments" mat-fab aria-labelledby="pause" @@ -92,6 +102,16 @@ </div> + <mat-menu #timeMenu="matMenu" xPosition="before"> + <div *ngFor="let periodItem of periodsList"> + <button mat-menu-item (click)="setTimePeriod(periodItem)" class="period" + [ngClass]="{'selected': periodItem === period}" + aria-labelledby="{{periodItem}}"> + <span>{{ ('comment-list.select-' + periodItem) | translate }}</span> + </button> + </div> + </mat-menu> + <mat-menu #sortMenu="matMenu" xPosition="before"> @@ -185,7 +205,7 @@ </button> <div *ngIf="!isLoading"> - <app-comment *ngFor="let current of hideCommentsList ? filteredComments : comments" + <app-comment *ngFor="let current of hideCommentsList ? filteredComments : commentsFilteredByTime" [comment]="current" [parseVote]="getVote(current)" [userRole]="userRole" @@ -197,7 +217,7 @@ </div> <!-- No Questions Present --> -<div *ngIf="comments && comments.length < 1 && !isLoading" +<div *ngIf="comments && commentsFilteredByTime.length < 1 && !isLoading" fxLayout="row" fxLayoutAlign="center center" class="no-comments"> @@ -224,4 +244,10 @@ <div id="play">{{'comment-list.a11y-play' | translate}}</div> <div id="close_search">{{'comment-list.a11y-close_search' | translate}}</div> <div id="new-comment">{{ 'comment-page.new-comment' | translate:{comment: newestComment} }}</div> + <div id="select-time">{{ 'comment-list.a11y-select-time' | translate }}</div> + <div id="select-time-1h">{{ 'comment-list.a11y-select-time-1h' | translate }}</div> + <div id="select-time-3h">{{ 'comment-list.a11y-select-time-3h' | translate }}</div> + <div id="select-time-1d">{{ 'comment-list.a11y-select-time-1d' | translate }}</div> + <div id="select-time-1w">{{ 'comment-list.a11y-select-time-1w' | translate }}</div> + <div id="select-time-all">{{ 'comment-list.a11y-select-time-all' | translate }}</div> </div> diff --git a/src/app/components/shared/comment-list/comment-list.component.scss b/src/app/components/shared/comment-list/comment-list.component.scss index 8e4057570..0e68b8c23 100644 --- a/src/app/components/shared/comment-list/comment-list.component.scss +++ b/src/app/components/shared/comment-list/comment-list.component.scss @@ -202,3 +202,7 @@ h3 { .visible { transform: scale(1.4); } + +.selected { + font-weight: bold; +} diff --git a/src/app/components/shared/comment-list/comment-list.component.ts b/src/app/components/shared/comment-list/comment-list.component.ts index 0dd540b55..1e96bd179 100644 --- a/src/app/components/shared/comment-list/comment-list.component.ts +++ b/src/app/components/shared/comment-list/comment-list.component.ts @@ -24,11 +24,20 @@ import { AuthenticationService } from '../../../services/http/authentication.ser import { Title } from '@angular/platform-browser'; import { TitleService } from '../../../services/util/title.service'; +export enum Period { + ONEHOUR = 'time-1h', + THREEHOURS = 'time-3h', + ONEDAY = 'time-1d', + ONEWEEK = 'time-1w', + ALL = 'time-all' +} + @Component({ selector: 'app-comment-list', templateUrl: './comment-list.component.html', styleUrls: ['./comment-list.component.scss'], }) + export class CommentListComponent implements OnInit, OnDestroy { @ViewChild('searchBox') searchField: ElementRef; @Input() user: User; @@ -36,6 +45,7 @@ export class CommentListComponent implements OnInit, OnDestroy { shortId: string; AppComponent = AppComponent; comments: Comment[] = []; + commentsFilteredByTime: Comment[] = []; room: Room; hideCommentsList = false; filteredComments: Comment[]; @@ -70,6 +80,8 @@ export class CommentListComponent implements OnInit, OnDestroy { newestComment: string; freeze = false; commentStream: Subscription; + periodsList = Object.values(Period); + period: Period = Period.ALL; constructor( private commentService: CommentService, @@ -162,7 +174,7 @@ export class CommentListComponent implements OnInit, OnDestroy { if (this.searchInput) { if (this.searchInput.length > 1) { this.hideCommentsList = true; - this.filteredComments = this.comments.filter(c => c.body.toLowerCase().includes(this.searchInput.toLowerCase())); + this.filteredComments = this.commentsFilteredByTime.filter(c => c.body.toLowerCase().includes(this.searchInput.toLowerCase())); } } else if (this.searchInput.length === 0 && this.currentFilter === '') { this.hideCommentsList = false; @@ -193,7 +205,7 @@ export class CommentListComponent implements OnInit, OnDestroy { this.setComments(this.comments.filter(x => x.score >= commentThreshold)); } } - this.sortComments(this.currentSort); + this.setTimePeriod(this.period); } getVote(comment: Comment): Vote { @@ -220,8 +232,8 @@ export class CommentListComponent implements OnInit, OnDestroy { }); this.announceNewComment(c.body); - - this.setComments(this.comments.concat(c)); + this.comments = this.comments.concat(c); + this.setComments(this.comments); break; case 'CommentPatched': // ToDo: Use a map for comments w/ key = commentId @@ -250,9 +262,10 @@ export class CommentListComponent implements OnInit, OnDestroy { case this.ack: const isNowAck = <boolean>value; if (!isNowAck) { - this.setComments(this.comments.filter(function (el) { + this.comments = this.comments.filter(function (el) { return el.id !== payload.id; - })); + }); + this.setTimePeriod(this.period); } break; case this.tag: @@ -282,9 +295,10 @@ export class CommentListComponent implements OnInit, OnDestroy { } break; } - this.filterComments(this.currentFilter); - this.sortComments(this.currentSort); - this.searchComments(); + this.setTimePeriod(this.period); + if (this.hideCommentsList) { + this.searchComments(); + } } openCreateDialog(): void { @@ -339,12 +353,12 @@ export class CommentListComponent implements OnInit, OnDestroy { filterComments(type: string, compare?: any): void { this.currentFilter = type; if (type === '') { - this.filteredComments = this.comments; + this.filteredComments = this.commentsFilteredByTime; this.hideCommentsList = false; this.currentFilter = ''; return; } - this.filteredComments = this.comments.filter(c => { + this.filteredComments = this.commentsFilteredByTime.filter(c => { switch (type) { case this.correct: return c.correct === CorrectWrong.CORRECT ? 1 : 0; @@ -387,7 +401,7 @@ export class CommentListComponent implements OnInit, OnDestroy { if (this.hideCommentsList === true) { this.filteredComments = this.sort(this.filteredComments, type); } else { - this.setComments(this.sort(this.comments, type)); + this.setComments(this.sort(this.commentsFilteredByTime, type)); } this.currentSort = type; } @@ -432,8 +446,8 @@ export class CommentListComponent implements OnInit, OnDestroy { } setComments(comments: Comment[]) { - this.titleService.attachTitle('(' + comments.length + ')'); - this.comments = comments; + this.commentsFilteredByTime = comments; + this.titleService.attachTitle('(' + this.commentsFilteredByTime.length + ')'); } /** @@ -454,4 +468,32 @@ export class CommentListComponent implements OnInit, OnDestroy { this.liveAnnouncer.announce(newCommentText).catch(err => { /* TODO error handling */ }); }, 450); } + + setTimePeriod(period: Period) { + this.period = period; + const currentTime = new Date(); + const hourInSeconds = 3600000; + let periodInSeconds; + if (period !== Period.ALL) { + switch (period) { + case Period.ONEHOUR: + periodInSeconds = hourInSeconds; + break; + case Period.THREEHOURS: + periodInSeconds = hourInSeconds * 2; + break; + case Period.ONEDAY: + periodInSeconds = hourInSeconds * 24; + break; + case Period.ONEWEEK: + periodInSeconds = hourInSeconds * 168; + } + this.commentsFilteredByTime = this.comments + .filter(c => new Date(c.timestamp).getTime() >= (currentTime.getTime() - periodInSeconds)); + } else { + this.commentsFilteredByTime = this.comments; + } + this.filterComments(this.currentFilter); + this.titleService.attachTitle('(' + this.commentsFilteredByTime.length + ')'); + } } -- GitLab