diff --git a/frontend/src/app/app.routes.ts b/frontend/src/app/app.routes.ts
index d89116b..e620ba4 100644
--- a/frontend/src/app/app.routes.ts
+++ b/frontend/src/app/app.routes.ts
@@ -25,6 +25,10 @@ export const routes: Routes = [
path: 'publications',
loadComponent: () => import('./pages/search-publications/search-publications.component').then(module => module.SearchPublicationsComponent)
},
+ {
+ path: 'my-publications',
+ loadChildren: () => import('./pages/my-publications/my-publications.routes').then(module => module.ROUTES)
+ },
{
path: '**',
loadComponent: () => import('./pages/home/home.component').then(module => module.HomeComponent)
diff --git a/frontend/src/app/components/header/header.component.html b/frontend/src/app/components/header/header.component.html
index df0f00c..5421b68 100644
--- a/frontend/src/app/components/header/header.component.html
+++ b/frontend/src/app/components/header/header.component.html
@@ -13,11 +13,24 @@
-
- Disconnect
-
-
+ @if (isAuthenticated) {
+
+
+
+
+ } @else {
Login
-
+ }
\ No newline at end of file
diff --git a/frontend/src/app/components/header/header.component.scss b/frontend/src/app/components/header/header.component.scss
index ab8db28..b325f3d 100644
--- a/frontend/src/app/components/header/header.component.scss
+++ b/frontend/src/app/components/header/header.component.scss
@@ -139,10 +139,65 @@ $headerHeight: 3.5em;
background-color: #5c6bc0;
}
}
+
+ button {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ min-width: 2.5em;
+ color: white;
+ margin: 0.5em 0.5em;
+ border-radius: 10em;
+ text-decoration: none;
+ padding: 0;
+ background-color: #3f51b5;
+ transition: background-color .2s ease-in-out;
+
+ &:hover {
+ background-color: #5c6bc0;
+ }
+
+ mat-icon {
+ margin: 0;
+ }
+ }
}
}
}
app-side-menu {
height: 100%;
+}
+
+.authenticated-user-menu {
+ display: flex;
+ flex-direction: column;
+ padding: 0.2em 0;
+
+ a {
+ flex: 1;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ text-decoration: none;
+ background-color: white;
+ color: black;
+ padding: 1em;
+ gap: .5em;
+ transition: background-color .2s ease-in-out, color .2s ease-in-out;
+
+ &:hover {
+ background-color: #5c6bc0;
+ color: white;
+ }
+
+ &.disconnection {
+ color: red;
+
+ &:hover {
+ background-color: red;
+ color: white;
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/frontend/src/app/components/header/header.component.ts b/frontend/src/app/components/header/header.component.ts
index 95ef6ef..66ff0b0 100644
--- a/frontend/src/app/components/header/header.component.ts
+++ b/frontend/src/app/components/header/header.component.ts
@@ -9,6 +9,8 @@ import { MatRippleModule } from '@angular/material/core';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { PublicationsSearchBarComponent } from '../publications-search-bar/publications-search-bar.component';
import { MatTooltipModule } from '@angular/material/tooltip';
+import { MatMenuModule } from '@angular/material/menu';
+import { User } from '../../core/model/User';
@Component({
selector: 'app-header',
@@ -17,12 +19,13 @@ import { MatTooltipModule } from '@angular/material/tooltip';
CommonModule,
MatButtonModule,
MatIconModule,
+ MatMenuModule,
+ MatRippleModule,
+ MatTooltipModule,
+ PublicationsSearchBarComponent,
+ ReactiveFormsModule,
RouterModule,
SideMenuComponent,
- MatRippleModule,
- ReactiveFormsModule,
- PublicationsSearchBarComponent,
- MatTooltipModule
],
templateUrl: './header.component.html',
styleUrl: './header.component.scss',
@@ -34,8 +37,4 @@ export class HeaderComponent {
get isAuthenticated(): boolean {
return this.authenticationService.isAuthenticated();
}
-
- searchPublications(): void {
-
- }
}
diff --git a/frontend/src/app/pages/my-publications/my-publications.component.html b/frontend/src/app/pages/my-publications/my-publications.component.html
new file mode 100644
index 0000000..4065830
--- /dev/null
+++ b/frontend/src/app/pages/my-publications/my-publications.component.html
@@ -0,0 +1,11 @@
+Your publications
+@if ((isLoading$ | async) === true) {
+ Publication loading...
+
+} @else {
+ @if ((isLoaded$ | async) === true) {
+
+ } @else {
+ There is no any publication...
+ }
+}
\ No newline at end of file
diff --git a/frontend/src/app/pages/my-publications/my-publications.component.scss b/frontend/src/app/pages/my-publications/my-publications.component.scss
new file mode 100644
index 0000000..b986f35
--- /dev/null
+++ b/frontend/src/app/pages/my-publications/my-publications.component.scss
@@ -0,0 +1,5 @@
+:host {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
\ No newline at end of file
diff --git a/frontend/src/app/pages/my-publications/my-publications.component.ts b/frontend/src/app/pages/my-publications/my-publications.component.ts
new file mode 100644
index 0000000..b595b48
--- /dev/null
+++ b/frontend/src/app/pages/my-publications/my-publications.component.ts
@@ -0,0 +1,36 @@
+import { Component, inject, OnInit } from "@angular/core";
+import { MatProgressSpinnerModule } from "@angular/material/progress-spinner";
+import { MyPublicationsService } from "./my-publications.service";
+import { Observable } from "rxjs";
+import { PublicationListComponent } from "../../components/publication-list/publication-list.component";
+import { Publication } from "../../core/rest-services/publications/model/publication";
+import { CommonModule } from "@angular/common";
+
+
+@Component({
+ selector: 'app-my-component',
+ standalone: true,
+ templateUrl: './my-publications.component.html',
+ styleUrl: './my-publications.component.scss',
+ imports: [CommonModule, MatProgressSpinnerModule, PublicationListComponent],
+ providers: [MyPublicationsService]
+})
+export class MyPublicationsComponent implements OnInit {
+ private readonly myPublicationsService = inject(MyPublicationsService);
+
+ get publications$(): Observable {
+ return this.myPublicationsService.publications$;
+ }
+
+ get isLoading$(): Observable {
+ return this.myPublicationsService.isLoading$;
+ }
+
+ get isLoaded$(): Observable {
+ return this.myPublicationsService.isLoaded$;
+ }
+
+ ngOnInit(): void {
+ this.myPublicationsService.loadAuthenticatedUserPublications();
+ }
+}
\ No newline at end of file
diff --git a/frontend/src/app/pages/my-publications/my-publications.routes.ts b/frontend/src/app/pages/my-publications/my-publications.routes.ts
new file mode 100644
index 0000000..d0fe316
--- /dev/null
+++ b/frontend/src/app/pages/my-publications/my-publications.routes.ts
@@ -0,0 +1,7 @@
+import { Route } from "@angular/router";
+import { authenticationGuard } from "../../core/guard/authentication.guard";
+import { MyPublicationsComponent } from "./my-publications.component";
+
+export const ROUTES: Route[] = [
+ { path: '', component: MyPublicationsComponent, canActivate: [authenticationGuard] }
+]
\ No newline at end of file
diff --git a/frontend/src/app/pages/my-publications/my-publications.service.ts b/frontend/src/app/pages/my-publications/my-publications.service.ts
new file mode 100644
index 0000000..e40ee03
--- /dev/null
+++ b/frontend/src/app/pages/my-publications/my-publications.service.ts
@@ -0,0 +1,57 @@
+import { inject, Injectable } from "@angular/core";
+import { PublicationRestService } from "../../core/rest-services/publications/publication.rest-service";
+import { AuthenticationService } from "../../core/service/authentication.service";
+import { BehaviorSubject, Observable } from "rxjs";
+import { Publication } from "../../core/rest-services/publications/model/publication";
+import { Router } from "@angular/router";
+import { MatSnackBar } from "@angular/material/snack-bar";
+
+@Injectable()
+export class MyPublicationsService {
+ private readonly authenticationService = inject(AuthenticationService);
+ private readonly publicationRestService = inject(PublicationRestService);
+ private readonly snackBar = inject(MatSnackBar);
+ private readonly router = inject(Router);
+ private publicationsSubject = new BehaviorSubject([]);
+ private isLoadingSubject = new BehaviorSubject(false);
+ private isLoadedSubject = new BehaviorSubject(false);
+
+ get publications$(): Observable {
+ return this.publicationsSubject.asObservable();
+ }
+
+ get isLoading$(): Observable {
+ return this.isLoadingSubject.asObservable();
+ }
+
+ get isLoaded$(): Observable {
+ return this.isLoadedSubject.asObservable();
+ }
+
+ loadAuthenticatedUserPublications(): void {
+ const authenticatedUser = this.authenticationService.getAuthenticatedUser();
+ if (authenticatedUser) {
+ this.isLoadingSubject.next(true);
+ this.isLoadedSubject.next(false);
+
+ const query = `author_id=${authenticatedUser.id}`;
+ this.publicationRestService.search(query)
+ .then(publications => {
+ this.publicationsSubject.next(publications);
+ })
+ .catch(error => {
+ const errorMessage = 'An error occurred while retrieving your publications...';
+ this.snackBar.open(errorMessage);
+ console.error(errorMessage, error);
+ })
+ .finally(() => {
+ this.isLoadingSubject.next(false);
+ this.isLoadedSubject.next(true);
+ });
+ } else {
+ this.authenticationService.unauthenticate();
+ this.snackBar.open('You are unauthenticated. Please, log-in first.', 'Close', { duration: 5000 });
+ this.router.navigate(['/login']);
+ }
+ }
+}
\ No newline at end of file