Skip to content

Commit

Permalink
Communication: Add undo button when deleting posts (#9624)
Browse files Browse the repository at this point in the history
  • Loading branch information
PaRangger authored Nov 3, 2024
1 parent 8c0eaed commit b63ac73
Show file tree
Hide file tree
Showing 27 changed files with 334 additions and 153 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
[isCommunicationPage]="isCommunicationPage"
[lastReadDate]="lastReadDate"
[hasChannelModerationRights]="hasChannelModerationRights"
[isDeleted]="isDeleted"
(isDeleteEvent)="onDeleteEvent(true)"
/>
@if (!createAnswerPostModal.isInputOpen) {
<div class="answer-post-content-margin">
Expand All @@ -15,6 +17,9 @@
[author]="posting.author"
[posting]="posting"
[isReply]="true"
[isDeleted]="isDeleted"
[deleteTimerInSeconds]="deleteTimerInSeconds"
(onUndoDeleteEvent)="onDeleteEvent(false)"
(userReferenceClicked)="userReferenceClicked.emit($event)"
(channelReferenceClicked)="channelReferenceClicked.emit($event)"
/>
Expand All @@ -23,14 +28,16 @@
<div class="answer-post-content-margin">
<ng-container #createEditAnswerPostContainer />
</div>
<div class="answer-post-content-margin">
<jhi-answer-post-footer
[isReadOnlyMode]="isReadOnlyMode"
[posting]="posting"
[isLastAnswer]="isLastAnswer"
[isThreadSidebar]="isThreadSidebar"
(openPostingCreateEditModal)="openPostingCreateEditModal.emit()"
/>
</div>
@if (!isDeleted) {
<div class="answer-post-content-margin" @fade>
<jhi-answer-post-footer
[isReadOnlyMode]="isReadOnlyMode"
[posting]="posting"
[isLastAnswer]="isLastAnswer"
[isThreadSidebar]="isThreadSidebar"
(openPostingCreateEditModal)="openPostingCreateEditModal.emit()"
/>
</div>
}
</div>
<jhi-answer-post-create-edit-modal #createAnswerPostModal [posting]="posting" [createEditAnswerPostContainerRef]="containerRef" />
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
@import 'bootstrap/scss/variables';
@import 'bootstrap/scss/mixins';

@import 'src/main/webapp/app/shared/metis/metis.component';

.answer-post {
background-color: var(--metis-answer-post-background-color);
border-radius: 7px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,27 @@ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, ViewCh
import { AnswerPost } from 'app/entities/metis/answer-post.model';
import { PostingDirective } from 'app/shared/metis/posting.directive';
import dayjs from 'dayjs/esm';
import { animate, style, transition, trigger } from '@angular/animations';

@Component({
selector: 'jhi-answer-post',
templateUrl: './answer-post.component.html',
styleUrls: ['./answer-post.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
animations: [
trigger('fade', [
transition(':enter', [style({ opacity: 0 }), animate('300ms ease-in', style({ opacity: 1 }))]),
transition(':leave', [animate('300ms ease-out', style({ opacity: 0 }))]),
]),
],
})
export class AnswerPostComponent extends PostingDirective<AnswerPost> {
@Input() lastReadDate?: dayjs.Dayjs;
@Input() isLastAnswer: boolean;
@Output() openPostingCreateEditModal = new EventEmitter<void>();
@Output() userReferenceClicked = new EventEmitter<string>();
@Output() channelReferenceClicked = new EventEmitter<number>();
isAnswerPost = true;

@Input()
isReadOnlyMode = false;
Expand Down
31 changes: 31 additions & 0 deletions src/main/webapp/app/shared/metis/metis.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
@import 'bootstrap/scss/variables';
@import 'bootstrap/scss/mixins';

$delete-delay-duration: 6s;

.post-result-information {
font-size: small;
font-style: italic;
Expand Down Expand Up @@ -98,3 +100,32 @@
font-size: 0.75rem !important;
}
}

.post-delete-button-background {
position: absolute;
top: 0;
left: 0;
bottom: 0;
z-index: 0;
background-color: rgba($primary, 0.3);
animation: increaseWidth $delete-delay-duration forwards linear;

@media (prefers-reduced-motion) {
animation: none;
}
}

.post-delete-button-label {
position: relative;
z-index: 1;
}

@keyframes increaseWidth {
from {
width: 0;
}

to {
width: 100%;
}
}
41 changes: 24 additions & 17 deletions src/main/webapp/app/shared/metis/post/post.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
[previewMode]="previewMode"
[readOnlyMode]="readOnlyMode"
[posting]="posting"
[isDeleted]="isDeleted"
[isCommunicationPage]="isCommunicationPage"
[hasChannelModerationRights]="hasChannelModerationRights"
(isModalOpen)="displayInlineInput = true"
[lastReadDate]="lastReadDate"
(isDeleteEvent)="onDeleteEvent(true)"
/>
</div>
<div class="align-items-center post-content-margin">
Expand Down Expand Up @@ -57,33 +59,38 @@
[isEdited]="!!posting.updatedDate"
[posting]="posting"
[isReply]="false"
[isDeleted]="isDeleted"
[deleteTimerInSeconds]="deleteTimerInSeconds"
(onUndoDeleteEvent)="onDeleteEvent(false)"
(userReferenceClicked)="onUserReferenceClicked($event)"
(channelReferenceClicked)="onChannelReferenceClicked($event)"
/>
}
</div>
</div>
@if (displayInlineInput && !readOnlyMode) {
@if (!isDeleted && displayInlineInput && !readOnlyMode) {
<div class="post-content-margin">
<jhi-message-inline-input [posting]="posting" (isModalOpen)="displayInlineInput = false" />
</div>
}
<div class="post-content-margin me-0 mt-2 justify-content-between" [ngClass]="{ 'mb-2': previewMode }">
<!-- Post reactions -->
@if (!previewMode) {
<jhi-post-reactions-bar
[lastReadDate]="lastReadDate"
[readOnlyMode]="readOnlyMode"
[posting]="posting"
[(showAnswers)]="showAnswers"
[sortedAnswerPosts]="sortedAnswerPosts"
[isCommunicationPage]="isCommunicationPage"
[isThreadSidebar]="isThreadSidebar"
(openPostingCreateEditModal)="openCreateAnswerPostModal()"
(openThread)="openThread.emit()"
/>
}
</div>
@if (!isDeleted) {
<div class="post-content-margin me-0 mt-2 justify-content-between" [ngClass]="{ 'mb-2': previewMode }" @fade>
<!-- Post reactions -->
@if (!previewMode) {
<jhi-post-reactions-bar
[lastReadDate]="lastReadDate"
[readOnlyMode]="readOnlyMode"
[posting]="posting"
[(showAnswers)]="showAnswers"
[sortedAnswerPosts]="sortedAnswerPosts"
[isCommunicationPage]="isCommunicationPage"
[isThreadSidebar]="isThreadSidebar"
(openPostingCreateEditModal)="openCreateAnswerPostModal()"
(openThread)="openThread.emit()"
/>
}
</div>
}
</div>
<jhi-post-footer
#postFooter
Expand Down
24 changes: 8 additions & 16 deletions src/main/webapp/app/shared/metis/post/post.component.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,6 @@
import {
AfterContentChecked,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
EventEmitter,
Input,
OnChanges,
OnInit,
Output,
ViewChild,
ViewContainerRef,
} from '@angular/core';
import { AfterContentChecked, ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, OnInit, Output, ViewChild, ViewContainerRef } from '@angular/core';
import { Post } from 'app/entities/metis/post.model';
import { PostingDirective } from 'app/shared/metis/posting.directive';
import { MetisService } from 'app/shared/metis/metis.service';
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { ContextInformation, DisplayPriority, PageType, RouteComponents } from '../metis.util';
import { faBullhorn, faCheckSquare } from '@fortawesome/free-solid-svg-icons';
Expand All @@ -26,12 +13,19 @@ import { MetisConversationService } from 'app/shared/metis/metis-conversation.se
import { getAsChannelDTO } from 'app/entities/metis/conversation/channel.model';
import { AnswerPost } from 'app/entities/metis/answer-post.model';
import { AnswerPostCreateEditModalComponent } from 'app/shared/metis/posting-create-edit-modal/answer-post-create-edit-modal/answer-post-create-edit-modal.component';
import { animate, style, transition, trigger } from '@angular/animations';

@Component({
selector: 'jhi-post',
templateUrl: './post.component.html',
styleUrls: ['./post.component.scss', './../metis.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
animations: [
trigger('fade', [
transition(':enter', [style({ opacity: 0 }), animate('300ms ease-in', style({ opacity: 1 }))]),
transition(':leave', [animate('300ms ease-out', style({ opacity: 0 }))]),
]),
],
})
export class PostComponent extends PostingDirective<Post> implements OnInit, OnChanges, AfterContentChecked {
@Input() lastReadDate?: dayjs.Dayjs;
Expand Down Expand Up @@ -64,8 +58,6 @@ export class PostComponent extends PostingDirective<Post> implements OnInit, OnC
faCheckSquare = faCheckSquare;

constructor(
private metisService: MetisService,
protected changeDetector: ChangeDetectorRef,
private oneToOneChatService: OneToOneChatService,
private metisConversationService: MetisConversationService,
private router: Router,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
@if (currentlyLoadedPosts) {
@if (isDeleted()) {
<span class="posting-content-undo-delete d-inline-flex align-items-center">
<span class="text-secondary" jhiTranslate="artemisApp.metis.post.deletedContent" [translateValues]="{ progress: deleteTimerInSeconds() }"></span>
<button class="btn btn-outline-primary btn-sm ms-2 position-relative" (click)="onUndoDeleteEvent.emit()">
<span class="post-delete-button-label" jhiTranslate="artemisApp.metis.post.undoDelete"></span>
<span class="post-delete-button-background"></span>
</button>
</span>
} @else if (currentlyLoadedPosts) {
<!-- in preview mode (showing similar posts during creation): content can be expanded and collapsed shown -->
@if (previewMode) {
<div class="pb-1">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, signal } from '@angular/core';
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, input, output, signal } from '@angular/core';
import { Params } from '@angular/router';
import { faAngleDown, faAngleUp } from '@fortawesome/free-solid-svg-icons';
import { Post } from 'app/entities/metis/post.model';
Expand All @@ -24,6 +24,9 @@ export class PostingContentComponent implements OnInit, OnChanges, OnDestroy {
@Input() isReply?: boolean;
@Output() userReferenceClicked = new EventEmitter<string>();
@Output() channelReferenceClicked = new EventEmitter<number>();
isDeleted = input<boolean>(false);
deleteTimerInSeconds = input<number>(0);
onUndoDeleteEvent = output<void>();

showContent = false;
currentlyLoadedPosts: Post[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
</div>
</div>
<ng-container class="list-answer-post">
@for (answerPost of sortedAnswerPosts; track $index; let isLastAnswer = $last) {
@for (answerPost of sortedAnswerPosts; track postsTrackByFn($index, answerPost); let isLastAnswer = $last) {
<jhi-answer-post
[lastReadDate]="lastReadDate"
[isReadOnlyMode]="readOnlyMode"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,8 @@ export class PostFooterComponent extends PostingFooterDirective<Post> implements
openCreateAnswerPostModal() {
this.createAnswerPostModalComponent.open();
}

protected postsTrackByFn(index: number, post: Post): number {
return post.id!;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
[authorName]="posting.author?.name"
[imageUrl]="posting.author?.imageUrl"
[isEditable]="currentUser !== undefined && posting.author.id === currentUser.id"
[isGray]="isDeleted()"
>
</jhi-profile-picture>
<span class="fs-small d-inline-flex flex-column align-items-start">
Expand All @@ -37,48 +38,47 @@
<span jhiTranslate="global.generic.new" class="badge bg-secondary hideAfter5Seconds"></span>
}
</div>

<div class="d-flex gap-2">
@if (mayEditOrDelete) {
<fa-icon
size="xs"
class="editIcon clickable icon"
[ngbTooltip]="'artemisApp.metis.editPosting' | artemisTranslate"
[icon]="faPencilAlt"
(click)="openPostingCreateEditModal.emit()"
/>
}
@if (mayEditOrDelete) {
<jhi-confirm-icon
iconSize="xs"
(confirmEvent)="deletePosting()"
[ngClass]="'deleteIcon clickable icon'"
[initialTooltip]="'artemisApp.metis.deleteAnswer' | artemisTranslate"
[confirmTooltip]="'artemisApp.metis.confirmDeleteAnswer' | artemisTranslate"
/>
}
@if (!isAnswerOfAnnouncement) {
<div id="toggleElement" class="resolve" [ngClass]="isAtLeastTutorInCourse || isAuthorOfOriginalPost ? 'clickable' : ''" (click)="toggleResolvesPost()">
@if (posting.resolvesPost) {
<div>
<fa-icon
class="resolved"
[icon]="faCheck"
[ngbTooltip]="
isAtLeastTutorInCourse || isAuthorOfOriginalPost
? ('artemisApp.metis.unmarkAsResolvingAnswerTooltip' | artemisTranslate)
: ('artemisApp.metis.resolvingAnswerTooltip' | artemisTranslate)
"
/>
</div>
} @else {
@if (isAtLeastTutorInCourse || isAuthorOfOriginalPost) {
@if (!isDeleted()) {
<div class="d-flex gap-2">
@if (mayEditOrDelete) {
<fa-icon
size="xs"
class="editIcon clickable icon"
[ngbTooltip]="'artemisApp.metis.editPosting' | artemisTranslate"
[icon]="faPencilAlt"
(click)="openPostingCreateEditModal.emit()"
/>
}
@if (mayEditOrDelete) {
<jhi-confirm-icon
iconSize="xs"
(confirmEvent)="deletePosting()"
[ngClass]="'deleteIcon clickable icon'"
[initialTooltip]="'artemisApp.metis.deleteAnswer' | artemisTranslate"
[confirmTooltip]="'artemisApp.metis.confirmDeleteAnswer' | artemisTranslate"
/>
}
@if (!isAnswerOfAnnouncement) {
<div id="toggleElement" class="resolve" [ngClass]="isAtLeastTutorInCourse || isAuthorOfOriginalPost ? 'clickable' : ''" (click)="toggleResolvesPost()">
@if (posting.resolvesPost) {
<div>
<fa-icon
class="resolved"
[icon]="faCheck"
[ngbTooltip]="
isAtLeastTutorInCourse || isAuthorOfOriginalPost
? ('artemisApp.metis.unmarkAsResolvingAnswerTooltip' | artemisTranslate)
: ('artemisApp.metis.resolvingAnswerTooltip' | artemisTranslate)
"
/>
</div>
} @else if (isAtLeastTutorInCourse || isAuthorOfOriginalPost) {
<div>
<fa-icon class="icon notResolved" [icon]="faCheck" [ngbTooltip]="'artemisApp.metis.markAsResolvingAnswerTooltip' | artemisTranslate" />
</div>
}
}
</div>
}
</div>
</div>
}
</div>
}
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export class AnswerPostHeaderComponent extends PostingHeaderDirective<AnswerPost
* invokes the metis service to delete an answer post
*/
deletePosting(): void {
this.metisService.deleteAnswerPost(this.posting);
this.isDeleteEvent.emit(true);
}

/**
Expand Down
Loading

0 comments on commit b63ac73

Please sign in to comment.