diff --git a/frontend/src/app/components/confirmation-dialog/confirmation-dialog.component.html b/frontend/src/app/components/confirmation-dialog/confirmation-dialog.component.html new file mode 100644 index 0000000..4c99664 --- /dev/null +++ b/frontend/src/app/components/confirmation-dialog/confirmation-dialog.component.html @@ -0,0 +1,10 @@ +

{{title}}

+

{{description}}

+ \ No newline at end of file diff --git a/frontend/src/app/components/confirmation-dialog/confirmation-dialog.component.scss b/frontend/src/app/components/confirmation-dialog/confirmation-dialog.component.scss new file mode 100644 index 0000000..00feaa3 --- /dev/null +++ b/frontend/src/app/components/confirmation-dialog/confirmation-dialog.component.scss @@ -0,0 +1,39 @@ +:host { + display: flex; + flex-direction: column; + text-align: center; + padding: 1em; + + footer { + display: flex; + flex-direction: row; + justify-content: space-between; + + button { + padding: .8em 1.2em; + border-radius: 10em; + border: none; + background-color: #3f51b5; + color: white; + transition: background-color .2s ease-in-out; + cursor: pointer; + display: flex; + justify-content: center; + align-items: center; + + &:hover { + background-color: #5b6ed8; + } + + &.secondary { + color: #3f51b5; + background-color: white; + + &:hover { + background-color: #f2f4ff; + cursor: pointer; + } + } + } + } +} \ No newline at end of file diff --git a/frontend/src/app/components/confirmation-dialog/confirmation-dialog.component.ts b/frontend/src/app/components/confirmation-dialog/confirmation-dialog.component.ts new file mode 100644 index 0000000..7636cef --- /dev/null +++ b/frontend/src/app/components/confirmation-dialog/confirmation-dialog.component.ts @@ -0,0 +1,35 @@ +import { Component, inject, Input } from "@angular/core"; +import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material/dialog"; + +export interface ConfirmationDialogData { + title: string; + description: string; +} + +@Component({ + selector: 'app-confirmation-dialog', + standalone: true, + templateUrl: './confirmation-dialog.component.html', + styleUrl: './confirmation-dialog.component.scss', + imports: [] +}) +export class ConfirmationDialog { + private readonly dialogRef = inject(MatDialogRef); + data: ConfirmationDialogData = inject(MAT_DIALOG_DATA); + + get title(): string { + return this.data.title; + } + + get description(): string { + return this.data.description; + } + + closeAndValidate(): void { + this.dialogRef.close(true); + } + + closeDialog(): void { + this.dialogRef.close(false); + } +} \ No newline at end of file diff --git a/frontend/src/app/components/publication-edition/publication-edition.service.ts b/frontend/src/app/components/publication-edition/publication-edition.service.ts index 1a144a7..ccb919f 100644 --- a/frontend/src/app/components/publication-edition/publication-edition.service.ts +++ b/frontend/src/app/components/publication-edition/publication-edition.service.ts @@ -1,14 +1,14 @@ -import { inject, Injectable, OnDestroy } from "@angular/core"; -import { ActivatedRoute, Router } from "@angular/router"; -import { PublicationRestService } from "../../core/rest-services/publications/publication.rest-service"; -import { MatSnackBar } from "@angular/material/snack-bar"; -import { MatDialog } from "@angular/material/dialog"; -import { BehaviorSubject, Observable, Subscription } from "rxjs"; -import { copy } from "../../core/utils/ObjectUtils"; -import { Publication } from "../../core/rest-services/publications/model/publication"; import { Location } from "@angular/common"; -import { PictureSelectionDialog } from "./picture-selection-dialog/picture-selection-dialog.component"; +import { inject, Injectable, OnDestroy } from "@angular/core"; +import { MatDialog } from "@angular/material/dialog"; +import { MatSnackBar } from "@angular/material/snack-bar"; +import { ActivatedRoute } from "@angular/router"; +import { BehaviorSubject, Observable, Subscription } from "rxjs"; +import { Publication } from "../../core/rest-services/publications/model/publication"; +import { PublicationRestService } from "../../core/rest-services/publications/publication.rest-service"; +import { copy } from "../../core/utils/ObjectUtils"; import { CodeBlockDialog } from "./code-block-dialog/code-block-dialog.component"; +import { PictureSelectionDialog } from "./picture-selection-dialog/picture-selection-dialog.component"; declare let Prism: any; @@ -58,7 +58,6 @@ export class PublicationEditionService implements OnDestroy { private readonly activatedRoute = inject(ActivatedRoute); private readonly publicationRestService = inject(PublicationRestService); private readonly location = inject(Location); - private readonly router = inject(Router); private readonly snackBar = inject(MatSnackBar); private readonly dialog = inject(MatDialog); @@ -265,23 +264,6 @@ export class PublicationEditionService implements OnDestroy { this._save(state); } - save(): void { - const state = this._state; - - this.isSavingSubject.next(true); - this.publicationRestService.update(state.publication) - .then(() => { - this.snackBar.open('Publication updated succesfully!', 'Close', { duration: 5000 }); - this.router.navigate(['/home']); - }) - .catch(error => { - const errorMessage = 'An error occured while saving publication modifications.'; - console.error(errorMessage, error); - this.snackBar.open(errorMessage, 'Close', { duration: 5000 }); - }) - .finally(() => this.isSavingSubject.next(false)); - } - loadPreview(): void { const state = this._state; diff --git a/frontend/src/app/core/rest-services/publications/publication.rest-service.ts b/frontend/src/app/core/rest-services/publications/publication.rest-service.ts index 91e94ec..e082a28 100644 --- a/frontend/src/app/core/rest-services/publications/publication.rest-service.ts +++ b/frontend/src/app/core/rest-services/publications/publication.rest-service.ts @@ -1,6 +1,6 @@ import { HttpClient, HttpParams } from '@angular/common/http'; import { Injectable, inject } from '@angular/core'; -import { lastValueFrom } from 'rxjs'; +import { last, lastValueFrom } from 'rxjs'; import { Publication } from './model/publication'; @Injectable({ @@ -35,4 +35,8 @@ export class PublicationRestService { const request = { text: publicationText }; return lastValueFrom(this.httpClient.post('/api/publications/preview', request)); } + + delete(publicationId: string): Promise { + return lastValueFrom(this.httpClient.delete(`/api/publications/${publicationId}`)); + } } diff --git a/frontend/src/app/pages/publication/publication.component.html b/frontend/src/app/pages/publication/publication.component.html index 37a0d6f..fad9d6f 100644 --- a/frontend/src/app/pages/publication/publication.component.html +++ b/frontend/src/app/pages/publication/publication.component.html @@ -25,7 +25,7 @@ @if (isAuthorAndUserEquals) { - diff --git a/frontend/src/app/pages/publication/publication.component.ts b/frontend/src/app/pages/publication/publication.component.ts index 8f66e5c..d66392d 100644 --- a/frontend/src/app/pages/publication/publication.component.ts +++ b/frontend/src/app/pages/publication/publication.component.ts @@ -1,14 +1,16 @@ import { Component, OnDestroy, OnInit, inject } from '@angular/core'; import { PublicationRestService } from '../../core/rest-services/publications/publication.rest-service'; -import { ActivatedRoute, RouterModule } from '@angular/router'; +import { ActivatedRoute, Router, RouterModule } from '@angular/router'; import { Subscription } from 'rxjs'; import { Publication } from '../../core/rest-services/publications/model/publication'; import { MatSnackBar } from '@angular/material/snack-bar'; -import { CommonModule } from '@angular/common'; +import { CommonModule, Location } from '@angular/common'; import { MatProgressSpinner } from '@angular/material/progress-spinner'; import { MatTooltip, MatTooltipModule } from '@angular/material/tooltip'; import { MatIcon } from '@angular/material/icon'; import { AuthenticationService } from '../../core/service/authentication.service'; +import { MatDialog } from '@angular/material/dialog'; +import { ConfirmationDialog } from '../../components/confirmation-dialog/confirmation-dialog.component'; declare let Prism: any; @@ -20,11 +22,14 @@ declare let Prism: any; styleUrl: './publication.component.scss' }) export class PublicationComponent implements OnInit, OnDestroy { - private activatedRoute = inject(ActivatedRoute); - private authenticationService = inject(AuthenticationService); - private publicationRestService = inject(PublicationRestService); + private readonly activatedRoute = inject(ActivatedRoute); + private readonly authenticationService = inject(AuthenticationService); + private readonly dialog = inject(MatDialog); + private readonly publicationRestService = inject(PublicationRestService); + private readonly location = inject(Location); + private readonly snackBar = inject(MatSnackBar); private paramMapSubscription?: Subscription; - private snackBar = inject(MatSnackBar); + private afterDialogCloseSubscription?: Subscription; isLoading: boolean = false; isAuthorAndUserEquals: boolean = false; publication?: Publication; @@ -57,5 +62,27 @@ export class PublicationComponent implements OnInit, OnDestroy { ngOnDestroy(): void { this.paramMapSubscription?.unsubscribe(); + this.afterDialogCloseSubscription?.unsubscribe(); + } + + deletePublication(): void { + const dialogRef = this.dialog.open( + ConfirmationDialog, + { + data: { + title: 'Publication deletion', + description: 'Are you sure you want to delete this publication?' + } + } + ); + + this.afterDialogCloseSubscription = dialogRef.afterClosed() + .subscribe(response => { + if (response && this.publication?.id) { + this.publicationRestService.delete(this.publication.id); + this.snackBar.open('Publication deleted', 'Close', { duration: 5000 }); + this.location.back(); + } + }); } }