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 @@
+
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 @@
-
-
-
{{ authorName }}
- {{ concernedAuthor?.role }}
-
-
- @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}`);