Add the post component.

This commit is contained in:
2019-02-10 15:58:14 +01:00
parent 284580c2ce
commit f45006acc0
5 changed files with 201 additions and 2 deletions

View File

@@ -14,6 +14,9 @@ import { appRoutes } from './app.routing';
// Guard
import { AuthGuard } from './core/guards/auth.guard';
// Interceptor
import { UnauthorizedInterceptor } from './core/interceptors/unauthorized.interceptor';
// Components
import { AppComponent } from './app.component';
import { HeaderComponent } from './header/header.component';
@@ -24,6 +27,7 @@ import { MyPostsComponent } from './posts/myPosts/my-posts.component';
import { AccountSettingsComponent } from './account-settings/account-settings.component';
import { ChangePasswordComponent } from './account-settings/change-password/change-password.component';
import { ProfilEditionComponent } from './account-settings/profil-edition/profil-edition.component';
import { PostComponent } from './posts/post.component';
// Reusable components
import { PostCardComponent } from './core/post-card/post-card.component';
@@ -37,7 +41,7 @@ import { LoginService } from './login/login.service';
import { MyPostsService } from './posts/myPosts/my-posts.service';
import { ChangePasswordService } from './account-settings/change-password/change-password.service';
import { ProfilEditionService } from './account-settings/profil-edition/profil-edition.service';
import { UnauthorizedInterceptor } from './core/interceptors/unauthorized.interceptor';
import { PostService } from './posts/post.service';
@NgModule({
declarations: [
@@ -51,7 +55,8 @@ import { UnauthorizedInterceptor } from './core/interceptors/unauthorized.interc
MyPostsComponent,
AccountSettingsComponent,
ChangePasswordComponent,
ProfilEditionComponent
ProfilEditionComponent,
PostComponent
],
imports: [
BrowserModule,
@@ -74,6 +79,7 @@ import { UnauthorizedInterceptor } from './core/interceptors/unauthorized.interc
MyPostsService,
ChangePasswordService,
ProfilEditionService,
PostService,
{ provide: HTTP_INTERCEPTORS, useClass: UnauthorizedInterceptor, multi: true }
],
bootstrap: [AppComponent]

View File

@@ -9,6 +9,7 @@ import { MyPostsComponent } from './posts/myPosts/my-posts.component';
import { AccountSettingsComponent } from './account-settings/account-settings.component';
import { ChangePasswordComponent } from './account-settings/change-password/change-password.component';
import { ProfilEditionComponent } from './account-settings/profil-edition/profil-edition.component';
import { PostComponent } from './posts/post.component';
export const appRoutes: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full' },
@@ -19,5 +20,6 @@ export const appRoutes: Routes = [
{ path: 'accountSettings', component: AccountSettingsComponent, canActivate: [AuthGuard] },
{ path: 'changePassword', component: ChangePasswordComponent, canActivate: [AuthGuard] },
{ path: 'profilEdit', component: ProfilEditionComponent, canActivate: [AuthGuard] },
{ path: 'posts/:postKey', component: PostComponent },
{ path: '**', redirectTo: '/home' }
];

View File

@@ -0,0 +1,67 @@
<div id="content" *ngIf="!notFound">
<app-spinner *ngIf="!loaded"></app-spinner>
<div class="card" *ngIf="loaded">
<img [src]="post?.image" class="img-fluid" alt="Post image">
<a *ngIf="owned" class="btn-card-floating waves-light white-text"
routerLink="/posts/update/{{post.key}}">
<i class="fa fa-pencil"></i>
</a>
<div class="card-body">
<h1 class="card-title">{{post.title}}</h1>
<h4>{{post.description}}</h4>
<hr/>
<div [innerHTML]="getContent()"></div>
</div>
<div class="card-data">
<img [src]="getAvatarUrl()"
class="author-img"
[alt]="post.author.name"
[mdbTooltip]="post.author.name"
placement="bottom"/>
Article écrit par {{post.author.name}}
<span class="creation-date-area">({{post.creationDate | date:'HH:mm:ss dd/MM/yyyy'}})</span>
<button *ngIf="owned" type="button" class="btn btn-danger waves-light float-right" (click)="alertDelete.show()" mdbRippleRadius>
<i class="fa fa-trash mr-1"></i> Supprimer
</button>
</div>
</div>
<div mdbModal #alertDelete="mdb-modal" class="modal fade" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-notify modal-danger" role="document">
<div class="modal-content">
<div class="modal-header">
<p class="heading lead">Suppression de l'article</p>
<button type="button" class="close" data-dismiss="modal" aria-label="Close" (click)="alertDelete.hide()">
<span aria-hidden="true" class="white-text">×</span>
</button>
</div>
<div class="modal-body">
<div class="text-center">
<p>Êtes vous sûr de vouloir supprimer cet article ?</p>
<p *ngIf="postDeletionFailed" class="red-text">
Une erreur est survenue lors de la suppression de l'article.
</p>
</div>
</div>
<div class="modal-footer">
<a type="button"
class="btn btn-outline-secondary-modal"
data-dismiss="modal"
(click)="alertDelete.hide()"
mdbRippleRadius>
Annuler
</a>
<a type="button" mdbRippleRadius
class="btn btn-primary-modal waves-light"
(click)="deletePost()">
<i class="fa fa-trash"></i> Supprimer
</a>
</div>
</div>
</div>
</div>
</div>
<!-- <app-not-found *ngIf="notFound"></app-not-found> -->

View File

@@ -0,0 +1,106 @@
import { Component, OnInit, SecurityContext, ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { HttpErrorResponse } from '@angular/common/http';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { Post, User } from '../core/entities';
import { PostService } from './post.service';
import { AuthService } from '../core/services/auth.service';
declare let Prism: any;
@Component({
selector: 'app-post',
templateUrl: './post.component.html',
styles: [`
.author-img {
width: 60px;
height: 60px;
border-radius: 50%;
margin-right: 15px;
}
.card .card-data {
padding: 15px;
background-color: #f5f5f5;
}
#content {
margin-bottom: 50px;
}
.creation-date-area {
color: #bdbdbd;
font-style: italic;
}
`]
})
export class PostComponent implements OnInit {
post: Post = new Post('', '', '', '', '', null, new User('', '', '', '', '', null, null, ''), null);
loaded: boolean;
notFound: boolean;
owned: boolean;
@ViewChild('alertDelete') alertDelete;
postDeletionFailed: boolean;
constructor(
private activatedRoute: ActivatedRoute,
private router: Router,
private postService: PostService,
private sanitizer: DomSanitizer,
private authService: AuthService
) {
this.loaded = false;
this.owned = false;
this.postDeletionFailed = false;
}
ngOnInit(): void {
this.postService.getPost(this.activatedRoute.snapshot.paramMap.get('postKey')).subscribe(post => {
this.post = post;
this.loaded = true;
this.owned = this.isOwned();
setTimeout(() => {
Prism.highlightAll();
}, 100);
}, error => {
if (error instanceof HttpErrorResponse && error.status === 404) {
this.notFound = true;
}
});
}
private isOwned(): boolean {
let result = false;
const connectedUser = this.authService.getUser();
if (connectedUser) {
result = this.post.author.key === connectedUser.key;
}
return result;
}
getContent(): SafeHtml {
return this.sanitizer.sanitize(SecurityContext.HTML, this.post.text);
}
getAvatarUrl(): string {
return this.post.author.image
? `./api/images/loadAvatar/${this.post.author.image}`
: './assets/images/default_user.png';
}
deletePost(): void {
this.postDeletionFailed = false;
this.postService.deletePost(this.post).subscribe(() => {
this.alertDelete.hide();
this.router.navigate(['/myPosts']);
}, error => {
this.postDeletionFailed = true;
setTimeout(() => {
this.postDeletionFailed = false;
}, 3500);
});
}
}

View File

@@ -0,0 +1,18 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Post } from '../core/entities';
@Injectable()
export class PostService {
constructor(private http: HttpClient) {}
getPost(postKey: string): Observable<Post> {
return this.http.get<Post>(`/api/posts/${postKey}`);
}
deletePost(postToDelete: Post): Observable<any> {
return this.http.delete(`/api/posts/${postToDelete.key}`);
}
}