Add "my-publications" page.
This commit is contained in:
@@ -25,6 +25,10 @@ export const routes: Routes = [
|
|||||||
path: 'publications',
|
path: 'publications',
|
||||||
loadComponent: () => import('./pages/search-publications/search-publications.component').then(module => module.SearchPublicationsComponent)
|
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: '**',
|
path: '**',
|
||||||
loadComponent: () => import('./pages/home/home.component').then(module => module.HomeComponent)
|
loadComponent: () => import('./pages/home/home.component').then(module => module.HomeComponent)
|
||||||
|
|||||||
@@ -13,11 +13,24 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<ng-container *ngIf="isAuthenticated; else anonymousRightMenu">
|
@if (isAuthenticated) {
|
||||||
<a [routerLink]="['/disconnect']" class="button" matRipple>Disconnect</a>
|
<button mat-button class="button" [matMenuTriggerFor]="authenticatedUserMenu">
|
||||||
</ng-container>
|
<mat-icon>more_vert</mat-icon>
|
||||||
<ng-template #anonymousRightMenu>
|
</button>
|
||||||
|
<mat-menu #authenticatedUserMenu="matMenu">
|
||||||
|
<div class="authenticated-user-menu">
|
||||||
|
<a [routerLink]="['/my-publications']" matRipple>
|
||||||
|
<mat-icon>description</mat-icon>
|
||||||
|
My publications
|
||||||
|
</a>
|
||||||
|
<a [routerLink]="['/disconnect']" matRipple class="disconnection">
|
||||||
|
<mat-icon>logout</mat-icon>
|
||||||
|
Disconnect
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</mat-menu>
|
||||||
|
} @else {
|
||||||
<a [routerLink]="['/login']" class="button" matRipple>Login</a>
|
<a [routerLink]="['/login']" class="button" matRipple>Login</a>
|
||||||
</ng-template>
|
}
|
||||||
</div>
|
</div>
|
||||||
<app-side-menu #sideMenu></app-side-menu>
|
<app-side-menu #sideMenu></app-side-menu>
|
||||||
@@ -139,10 +139,65 @@ $headerHeight: 3.5em;
|
|||||||
background-color: #5c6bc0;
|
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 {
|
app-side-menu {
|
||||||
height: 100%;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,8 @@ import { MatRippleModule } from '@angular/material/core';
|
|||||||
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
||||||
import { PublicationsSearchBarComponent } from '../publications-search-bar/publications-search-bar.component';
|
import { PublicationsSearchBarComponent } from '../publications-search-bar/publications-search-bar.component';
|
||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
|
import { User } from '../../core/model/User';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-header',
|
selector: 'app-header',
|
||||||
@@ -17,12 +19,13 @@ import { MatTooltipModule } from '@angular/material/tooltip';
|
|||||||
CommonModule,
|
CommonModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
|
MatMenuModule,
|
||||||
|
MatRippleModule,
|
||||||
|
MatTooltipModule,
|
||||||
|
PublicationsSearchBarComponent,
|
||||||
|
ReactiveFormsModule,
|
||||||
RouterModule,
|
RouterModule,
|
||||||
SideMenuComponent,
|
SideMenuComponent,
|
||||||
MatRippleModule,
|
|
||||||
ReactiveFormsModule,
|
|
||||||
PublicationsSearchBarComponent,
|
|
||||||
MatTooltipModule
|
|
||||||
],
|
],
|
||||||
templateUrl: './header.component.html',
|
templateUrl: './header.component.html',
|
||||||
styleUrl: './header.component.scss',
|
styleUrl: './header.component.scss',
|
||||||
@@ -34,8 +37,4 @@ export class HeaderComponent {
|
|||||||
get isAuthenticated(): boolean {
|
get isAuthenticated(): boolean {
|
||||||
return this.authenticationService.isAuthenticated();
|
return this.authenticationService.isAuthenticated();
|
||||||
}
|
}
|
||||||
|
|
||||||
searchPublications(): void {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<h1>Your publications</h1>
|
||||||
|
@if ((isLoading$ | async) === true) {
|
||||||
|
<h2>Publication loading...</h2>
|
||||||
|
<mat-spinner></mat-spinner>
|
||||||
|
} @else {
|
||||||
|
@if ((isLoaded$ | async) === true) {
|
||||||
|
<app-publication-list [publications$]="publications$"></app-publication-list>
|
||||||
|
} @else {
|
||||||
|
<h2>There is no any publication...</h2>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
@@ -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<Publication[]> {
|
||||||
|
return this.myPublicationsService.publications$;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isLoading$(): Observable<boolean> {
|
||||||
|
return this.myPublicationsService.isLoading$;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isLoaded$(): Observable<boolean> {
|
||||||
|
return this.myPublicationsService.isLoaded$;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.myPublicationsService.loadAuthenticatedUserPublications();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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] }
|
||||||
|
]
|
||||||
@@ -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<Publication[]>([]);
|
||||||
|
private isLoadingSubject = new BehaviorSubject<boolean>(false);
|
||||||
|
private isLoadedSubject = new BehaviorSubject<boolean>(false);
|
||||||
|
|
||||||
|
get publications$(): Observable<Publication[]> {
|
||||||
|
return this.publicationsSubject.asObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
get isLoading$(): Observable<boolean> {
|
||||||
|
return this.isLoadingSubject.asObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
get isLoaded$(): Observable<boolean> {
|
||||||
|
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']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user