From 2017b16d4c45d3e01a4dc0528db7551870a55082 Mon Sep 17 00:00:00 2001 From: Guams Date: Wed, 22 Jan 2025 20:50:53 +0100 Subject: [PATCH] update du nom d'utilisateur ainsi que de la photo de profil --- src/app/components/header/header.component.ts | 6 +- .../post-form/post-form.component.css | 20 +++ .../post-form/post-form.component.html | 9 +- .../post-form/post-form.component.ts | 15 +-- .../update-profile-form.component.css | 38 ++++++ .../update-profile-form.component.html | 28 ++++ .../update-profile-form.component.ts | 121 ++++++++++++++++++ src/app/models/author.ts | 2 +- src/app/pages/home/home.component.css | 10 +- src/app/pages/login/login.component.ts | 3 +- src/app/pages/logout/logout.component.ts | 5 +- src/app/pages/profile/profile.component.css | 17 ++- src/app/pages/profile/profile.component.html | 54 +++++--- src/app/pages/profile/profile.component.ts | 13 +- src/app/services/author.service.ts | 24 ++++ 15 files changed, 321 insertions(+), 44 deletions(-) create mode 100644 src/app/components/update-profile-form/update-profile-form.component.css create mode 100644 src/app/components/update-profile-form/update-profile-form.component.html create mode 100644 src/app/components/update-profile-form/update-profile-form.component.ts diff --git a/src/app/components/header/header.component.ts b/src/app/components/header/header.component.ts index 4ed7b30..b90aa88 100644 --- a/src/app/components/header/header.component.ts +++ b/src/app/components/header/header.component.ts @@ -46,7 +46,7 @@ export class HeaderComponent { if (author.role === 'WRITER') { return [ ...commonItems, - this.getWriterMenu(author), + this.getWriterMenu(), this.getUserMenu(author) ]; } else if (author.role === 'ADMIN') { @@ -65,7 +65,7 @@ export class HeaderComponent { return commonItems; } - private getWriterMenu(author: Author): MenuItem { + private getWriterMenu(): MenuItem { return { label: 'Mes posts', icon: 'pi pi-file-edit', @@ -97,7 +97,7 @@ export class HeaderComponent { private getUserMenu(author: Author): MenuItem { return { - label: author.name.toUpperCase(), + label: 'MOI', icon: 'pi pi-user', items: [ { label: 'Voir mon profil', icon: 'pi pi-user', routerLink: [`/profile`, `${author.id}`] }, diff --git a/src/app/components/post-form/post-form.component.css b/src/app/components/post-form/post-form.component.css index 5157b40..4353db5 100644 --- a/src/app/components/post-form/post-form.component.css +++ b/src/app/components/post-form/post-form.component.css @@ -16,3 +16,23 @@ form { .send-button { align-self: center; } + +.add-file-button { + margin: 0; + font-size: 40px; + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + flex-direction: row; + gap: 1rem; +} + +.pi-plus { + font-size: 40px; +} + +.add-file-button :hover { + cursor: pointer; +} diff --git a/src/app/components/post-form/post-form.component.html b/src/app/components/post-form/post-form.component.html index 1a86d95..0fdaae2 100644 --- a/src/app/components/post-form/post-form.component.html +++ b/src/app/components/post-form/post-form.component.html @@ -17,7 +17,14 @@ [showCancelButton]="false" chooseLabel="Sélectionner une image" (onSelect)="onSelected($event)"> - + + + @if (!files?.length) { +
+ Ajouter un fichier +
+ } +
diff --git a/src/app/components/post-form/post-form.component.ts b/src/app/components/post-form/post-form.component.ts index bd9b42b..9f0ab5c 100644 --- a/src/app/components/post-form/post-form.component.ts +++ b/src/app/components/post-form/post-form.component.ts @@ -11,6 +11,7 @@ import { EditorModule } from 'primeng/editor'; import { Router } from '@angular/router'; import {Author} from '../../models/author'; import {AuthorService} from '../../services/author.service'; +import {JsonPipe} from '@angular/common'; @Component({ selector: 'app-post-form', @@ -20,7 +21,8 @@ import {AuthorService} from '../../services/author.service'; InputTextModule, InputTextareaModule, FileUploadModule, - EditorModule + EditorModule, + JsonPipe ], templateUrl: './post-form.component.html', styleUrls: ['./post-form.component.css'] @@ -91,13 +93,6 @@ export class PostFormComponent implements OnDestroy { } } - // transformParagraphs(): void { - // if (this.body) { - // this.body = this.body.replace(/ /g, ' '); - // console.log(this.body); - // } - // } - onSubmit(): void { if (this.form.valid && this.uploadedFile) { const formData = this.form.value; @@ -143,6 +138,10 @@ export class PostFormComponent implements OnDestroy { } } + choose(callback: Function) { + callback(); + } + successMessage(summary: string, detail: string): void { this.messageService.add({ severity: 'success', diff --git a/src/app/components/update-profile-form/update-profile-form.component.css b/src/app/components/update-profile-form/update-profile-form.component.css new file mode 100644 index 0000000..ad72cbe --- /dev/null +++ b/src/app/components/update-profile-form/update-profile-form.component.css @@ -0,0 +1,38 @@ +.form-container { + margin-top: 2em; + display: flex; + justify-content: center; + align-items: center; +} + +.form { + width: 100%; + max-width: 50em; + display: flex; + flex-direction: column; + gap:1em; +} + +.send-button { + align-self: center; +} + +.add-file-button { + margin: 0; + font-size: 25px; + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + flex-direction: row; + gap: 1rem; +} + +.pi-plus { + font-size: 25px; +} + +.add-file-button :hover { + cursor: pointer; +} diff --git a/src/app/components/update-profile-form/update-profile-form.component.html b/src/app/components/update-profile-form/update-profile-form.component.html new file mode 100644 index 0000000..16648e3 --- /dev/null +++ b/src/app/components/update-profile-form/update-profile-form.component.html @@ -0,0 +1,28 @@ +
+
+ + + + + + + + + + @if (!files?.length) { +
+ Ajouter un fichier +
+ } +
+
+ +
+
diff --git a/src/app/components/update-profile-form/update-profile-form.component.ts b/src/app/components/update-profile-form/update-profile-form.component.ts new file mode 100644 index 0000000..954ff77 --- /dev/null +++ b/src/app/components/update-profile-form/update-profile-form.component.ts @@ -0,0 +1,121 @@ +import {Component, EventEmitter, Input, OnDestroy, Output} from '@angular/core'; +import {Button} from 'primeng/button'; +import {InputTextModule} from 'primeng/inputtext'; +import {FormBuilder, FormGroup, ReactiveFormsModule, Validators} from '@angular/forms'; +import {SelectButtonModule} from 'primeng/selectbutton'; +import {Subscription, switchMap} from 'rxjs'; +import {AuthorService} from '../../services/author.service'; +import {MessageService} from 'primeng/api'; +import {FileSelectEvent, FileUploadModule} from 'primeng/fileupload'; +import {CookieService} from 'ngx-cookie-service'; +import {Author} from '../../models/author'; +import {Router} from '@angular/router'; + +@Component({ + selector: 'app-update-profile', + standalone: true, + imports: [ + Button, + InputTextModule, + ReactiveFormsModule, + SelectButtonModule, + FileUploadModule + ], + templateUrl: './update-profile-form.component.html', + styleUrl: './update-profile-form.component.css' +}) +export class UpdateProfileFormComponent implements OnDestroy { + @Input() username: string = ""; + @Input() authorId: string = ""; + password: string = ""; + passwordConfirm: string = ""; + @Output() updatedAuthorEvent: EventEmitter = new EventEmitter(); + uploadedFile: File | undefined; + subs: Subscription[] = []; + form: FormGroup; + + constructor(private formBuilder: FormBuilder, + private authorService: AuthorService, + private messageService: MessageService, + private cookieService: CookieService, + private router: Router, + ) { + this.form = this.formBuilder.group({ + username: ['', [Validators.required, Validators.maxLength(255)]], + password: ['', [Validators.required, Validators.maxLength(50)]], + passwordConfirm: ['', [Validators.required, Validators.maxLength(50)]], + }); + } + + onSelected(event: FileSelectEvent): void { + if (event.currentFiles && event.currentFiles.length > 0) { + this.uploadedFile = event.currentFiles[0]; + } + } + + choose(callback: Function) { + callback(); + } + + successMessage(summary: string, detail: string): void { + this.messageService.add({ + severity: 'success', + summary: summary, + detail: detail, + life: 3000, + closable: false + }); + } + + failureMessage(summary: string, detail: string): void { + this.messageService.add({ + severity: 'error', + summary: summary, + detail: detail, + life: 3000, + closable: false + }); + } + + onSubmit() { + const token: string | undefined = this.cookieService.get('token'); + if (this.form.valid && token && this.password === this.passwordConfirm) { + const newUsername = this.form.value.username; + if (this.uploadedFile) { + this.subs.push(this.authorService.updateAuthor(this.authorId, token, newUsername, this.password).pipe( + switchMap((_) => { + return this.authorService.changeAvatar(this.authorId, this.uploadedFile, token) + }) + ).subscribe({ + next: (author: Author) => { + this.successMessage("Mise à jour réussie", "Profil mit à jour avec succès"); + this.updatedAuthorEvent.emit(author); + this.cookieService.set('author', JSON.stringify(author)); + this.router.navigate(['/']); + }, + error: (err) => { + this.failureMessage("Erreur", err.message); + } + })); + } else { + this.subs.push(this.authorService.updateAuthor(this.authorId, token, newUsername, this.password).subscribe({ + next: (author: Author) => { + this.successMessage("Mise à jour réussie", "Profil mit à jour avec succès"); + this.updatedAuthorEvent.emit(author); + this.cookieService.set('author', JSON.stringify(author)); + this.router.navigate(['/']); + }, + error: (err) => { + this.failureMessage("Erreur", err.message); + } + })); + } + } + + } + + ngOnDestroy(): void { + this.subs.forEach(sub => sub.unsubscribe()) + } + +} diff --git a/src/app/models/author.ts b/src/app/models/author.ts index 2b6c06a..7a7c995 100644 --- a/src/app/models/author.ts +++ b/src/app/models/author.ts @@ -1,6 +1,6 @@ export interface Author { id: string name: string - avatar: string + profilePicture: string role: string } diff --git a/src/app/pages/home/home.component.css b/src/app/pages/home/home.component.css index f087727..0766bf7 100644 --- a/src/app/pages/home/home.component.css +++ b/src/app/pages/home/home.component.css @@ -1,5 +1,7 @@ -.main-content { - margin: auto; - width: 45%; - padding: 2rem; +@media only screen and (min-width: 1080px) { + .main-content { + margin: auto; + width: 45%; + padding: 2rem; + } } diff --git a/src/app/pages/login/login.component.ts b/src/app/pages/login/login.component.ts index 220cfd3..a0fd7a9 100644 --- a/src/app/pages/login/login.component.ts +++ b/src/app/pages/login/login.component.ts @@ -47,8 +47,8 @@ export class LoginComponent implements OnDestroy { })) .subscribe({ next: (author: Author) => { + console.log(author) this.cookieService.set("author", JSON.stringify(author)); - this.cookieService.set("just-authenticated", "true"); this.getAuthorCookie(); this.router.navigate(['/']).then(() => { this.successMessage('Connecté avec succès', 'Heureux de vous revoir ' + this.actualAuthor?.name) @@ -57,7 +57,6 @@ export class LoginComponent implements OnDestroy { error: (err) => this.failureMessage('Erreur de connexion', err.message) }) ); - } else { this.failureMessage('Erreur de connexion', 'Les deux mots de passe ne correspondent pas') } diff --git a/src/app/pages/logout/logout.component.ts b/src/app/pages/logout/logout.component.ts index fc88d19..9629dbc 100644 --- a/src/app/pages/logout/logout.component.ts +++ b/src/app/pages/logout/logout.component.ts @@ -19,7 +19,10 @@ export class LogoutComponent implements OnInit{ private messageService: MessageService, private router: Router) { } ngOnInit(): void { - this.cookiesService.deleteAll("/", "localhost"); + // this.cookiesService.deleteAll("/", "localhost"); // deleteAll est bugué + this.cookiesService.delete('author') + this.cookiesService.delete('just-authenticated') + this.cookiesService.delete('token') this.router.navigate(['/']).then(() => this.successMessage('Déconnexion', 'Vous avez été deconnecté avec succès')); } diff --git a/src/app/pages/profile/profile.component.css b/src/app/pages/profile/profile.component.css index e20246f..fb3fac2 100644 --- a/src/app/pages/profile/profile.component.css +++ b/src/app/pages/profile/profile.component.css @@ -1,10 +1,7 @@ .content { margin-top: 5rem; - width: 45%; display: flex; - align-items: center; - flex-direction: row; - justify-content: space-between; + justify-content: center; gap: 3em; } @@ -17,7 +14,17 @@ em { margin: 0; } -.user-info { +.user-infos { + margin-bottom: 4rem; + display: flex; + align-self: stretch; + justify-content: space-between; + flex-direction: row; +} + +.panel { + gap: 0.5rem; display: flex; flex-direction: column; + align-items: center; } diff --git a/src/app/pages/profile/profile.component.html b/src/app/pages/profile/profile.component.html index 9d8de28..4098cf3 100644 --- a/src/app/pages/profile/profile.component.html +++ b/src/app/pages/profile/profile.component.html @@ -1,21 +1,39 @@ -
- -
- @if (concernedAuthor?.avatar) { - - } @else { - - } -
+@if (concernedAuthor) { +
+
+
+
+

{{ authorName }}

+ {{ concernedAuthor.role }} +
+
+ @if (concernedAuthor.profilePicture) { + + } @else { + + } +
+
+ + @if (actualAuthor) { + @if (concernedAuthor.id === actualAuthor.id) { + + + + + + - - - - - -
+ + } + } +
+
+} @else { +

Loading...

+} diff --git a/src/app/pages/profile/profile.component.ts b/src/app/pages/profile/profile.component.ts index d327301..594bec3 100644 --- a/src/app/pages/profile/profile.component.ts +++ b/src/app/pages/profile/profile.component.ts @@ -8,6 +8,8 @@ import {AuthorService} from '../../services/author.service'; import {AvatarModule} from 'primeng/avatar'; import {CardModule} from 'primeng/card'; import {Button} from 'primeng/button'; +import {DialogModule} from 'primeng/dialog'; +import {UpdateProfileFormComponent} from '../../components/update-profile-form/update-profile-form.component'; @Component({ selector: 'app-profile', @@ -16,7 +18,9 @@ import {Button} from 'primeng/button'; HeaderComponent, AvatarModule, CardModule, - Button + Button, + DialogModule, + UpdateProfileFormComponent ], templateUrl: './profile.component.html', styleUrl: './profile.component.css' @@ -26,6 +30,8 @@ export class ProfileComponent implements OnDestroy { concernedAuthor: Author | undefined; authorName: string = ""; subs: Subscription[] = []; + updateProfileDialog: boolean = false; + changePasswordDialog: boolean = false; constructor(private route: ActivatedRoute, private authorService: AuthorService, @@ -41,6 +47,11 @@ export class ProfileComponent implements OnDestroy { } } + updateAuthor(author: Author) { + this.concernedAuthor = author; + this.actualAuthor = author; + } + ngOnDestroy(): void { this.subs.forEach(sub => sub.unsubscribe()); } diff --git a/src/app/services/author.service.ts b/src/app/services/author.service.ts index 02ec70f..8291e88 100644 --- a/src/app/services/author.service.ts +++ b/src/app/services/author.service.ts @@ -34,6 +34,30 @@ export class AuthorService { return this.httpClient.put(`${this.url}/${authorId}/posts`, postId, httpOptions); } + updateAuthor(authorId: string, token: string, username: string, password: string): Observable { + const httpOptions = { + headers: new HttpHeaders({ + 'Authorization': `Bearer ${token}` + }) + } + return this.httpClient.put(`${this.url}/${authorId}`, {name: username, password: password}, httpOptions); + } + + changeAvatar(id: string | undefined, image: File | undefined, token: string) { + if (image) { + const formData: FormData = new FormData(); + formData.append('avatar', image); + const httpOptions = { + headers: new HttpHeaders({ + 'Authorization': `Bearer ${token}` + }) + }; + return this.httpClient.put(`${this.url}/${id}/avatar`, formData, httpOptions); + } else { + throw new Error('Image doesn\'t exist'); + } + } + getAuthor(id: string | null): Observable { if (id) { return this.httpClient.get(`${this.url}/${id}`);