From cd7b8a237158b7c5eaea6c3f5cb2834e4c65295c Mon Sep 17 00:00:00 2001 From: macfleury-2000 <70949353+macfleury-2000@users.noreply.github.com> Date: Thu, 10 Jun 2021 13:37:20 +0200 Subject: [PATCH 01/30] added page and fixed routing --- src/app/app-routing.module.ts | 5 +++++ .../user-project/user-project.component.html | 18 ++++++++++++++++++ .../user-project/user-project.component.scss | 0 .../user-project/user-project.component.ts | 15 +++++++++++++++ src/app/modules/user/user-routing.module.ts | 14 ++++++++++++++ src/app/modules/user/user.module.ts | 15 +++++++++++++++ 6 files changed, 67 insertions(+) create mode 100644 src/app/modules/user/user-project/user-project.component.html create mode 100644 src/app/modules/user/user-project/user-project.component.scss create mode 100644 src/app/modules/user/user-project/user-project.component.ts create mode 100644 src/app/modules/user/user-routing.module.ts create mode 100644 src/app/modules/user/user.module.ts diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 3c2804b1..b4d350e0 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -21,6 +21,7 @@ import { AuthCallbackComponent } from './components/auth-callback/auth-callback. import { NotFoundComponent } from './components/not-found/not-found.component'; import { PrivacyPolicyComponent } from './components/privacy-policy/privacy-policy.component'; import { MainComponent } from './modules/home/main/main.component'; +// import { UserModule } from './modules/user/user.module'; const routes: Routes = [ {path: '', redirectTo: '/home', pathMatch: 'full'}, @@ -31,6 +32,10 @@ const routes: Routes = [ path: 'project', loadChildren: () => import('./modules/project/project.module').then((m) => m.ProjectModule), }, + { + path: 'user', + loadChildren: () => import('./modules/user/user.module').then((m) => m.UserModule), + }, { path: 'account', loadChildren: () => import('./modules/account/account.module').then((m) => m.AccountModule), diff --git a/src/app/modules/user/user-project/user-project.component.html b/src/app/modules/user/user-project/user-project.component.html new file mode 100644 index 00000000..0f72ab5f --- /dev/null +++ b/src/app/modules/user/user-project/user-project.component.html @@ -0,0 +1,18 @@ + + diff --git a/src/app/modules/user/user-project/user-project.component.scss b/src/app/modules/user/user-project/user-project.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/modules/user/user-project/user-project.component.ts b/src/app/modules/user/user-project/user-project.component.ts new file mode 100644 index 00000000..177936b7 --- /dev/null +++ b/src/app/modules/user/user-project/user-project.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-user-project', + templateUrl: './user-project.component.html', + styleUrls: ['./user-project.component.scss'] +}) +export class UserProjectComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/src/app/modules/user/user-routing.module.ts b/src/app/modules/user/user-routing.module.ts new file mode 100644 index 00000000..f120eb50 --- /dev/null +++ b/src/app/modules/user/user-routing.module.ts @@ -0,0 +1,14 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; +import { UserProjectComponent } from './user-project/user-project.component'; + + +const routes: Routes = [ + { path: 'projects', component: UserProjectComponent }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class UserRoutingModule { } diff --git a/src/app/modules/user/user.module.ts b/src/app/modules/user/user.module.ts new file mode 100644 index 00000000..ff66c245 --- /dev/null +++ b/src/app/modules/user/user.module.ts @@ -0,0 +1,15 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { UserRoutingModule } from './user-routing.module'; +import { UserProjectComponent } from './user-project/user-project.component'; + + +@NgModule({ + declarations: [UserProjectComponent], + imports: [ + CommonModule, + UserRoutingModule + ] +}) +export class UserModule { } From 743d9dc357ebee15d5f4ea2c1a7893c82f6d25f0 Mon Sep 17 00:00:00 2001 From: macfleury-2000 <70949353+macfleury-2000@users.noreply.github.com> Date: Fri, 11 Jun 2021 10:14:15 +0200 Subject: [PATCH 02/30] completed surrounding HTML, first try call service --- src/app/app.component.css | 19 ++ src/app/app.component.css.map | 9 + .../auth-callback/auth-callback.component.css | 19 ++ .../auth-callback.component.css.map | 9 + src/app/modules/home/main/main.component.css | 1 + .../modules/home/main/main.component.css.map | 9 + .../project/overview/overview.component.ts | 2 +- .../user-project/user-project.component.html | 92 ++++++++ .../user-project/user-project.component.scss | 201 ++++++++++++++++++ .../user-project/user-project.component.ts | 78 ++++++- src/app/services/user.service.ts | 5 + 11 files changed, 439 insertions(+), 5 deletions(-) create mode 100644 src/app/app.component.css create mode 100644 src/app/app.component.css.map create mode 100644 src/app/components/auth-callback/auth-callback.component.css create mode 100644 src/app/components/auth-callback/auth-callback.component.css.map create mode 100644 src/app/modules/home/main/main.component.css create mode 100644 src/app/modules/home/main/main.component.css.map diff --git a/src/app/app.component.css b/src/app/app.component.css new file mode 100644 index 00000000..7c75283a --- /dev/null +++ b/src/app/app.component.css @@ -0,0 +1,19 @@ +/* + * + * Digital Excellence Copyright (C) 2020 Brend Smits + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You can find a copy of the GNU Lesser General Public License + * along with this program, in the LICENSE.md file in the root project directory. + * If not, see https://www.gnu.org/licenses/lgpl-3.0.txt + * + */ +/*# sourceMappingURL=app.component.css.map */ \ No newline at end of file diff --git a/src/app/app.component.css.map b/src/app/app.component.css.map new file mode 100644 index 00000000..4bb73eb0 --- /dev/null +++ b/src/app/app.component.css.map @@ -0,0 +1,9 @@ +{ + "version": 3, + "mappings": "AAAA;;;;;;;;;;;;;;;;;GAiBG", + "sources": [ + "app.component.scss" + ], + "names": [], + "file": "app.component.css" +} \ No newline at end of file diff --git a/src/app/components/auth-callback/auth-callback.component.css b/src/app/components/auth-callback/auth-callback.component.css new file mode 100644 index 00000000..7b95518c --- /dev/null +++ b/src/app/components/auth-callback/auth-callback.component.css @@ -0,0 +1,19 @@ +/* + * + * Digital Excellence Copyright (C) 2020 Brend Smits + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You can find a copy of the GNU Lesser General Public License + * along with this program, in the LICENSE.md file in the root project directory. + * If not, see https://www.gnu.org/licenses/lgpl-3.0.txt + * + */ +/*# sourceMappingURL=auth-callback.component.css.map */ \ No newline at end of file diff --git a/src/app/components/auth-callback/auth-callback.component.css.map b/src/app/components/auth-callback/auth-callback.component.css.map new file mode 100644 index 00000000..d10a1ce6 --- /dev/null +++ b/src/app/components/auth-callback/auth-callback.component.css.map @@ -0,0 +1,9 @@ +{ + "version": 3, + "mappings": "AAAA;;;;;;;;;;;;;;;;;GAiBG", + "sources": [ + "auth-callback.component.scss" + ], + "names": [], + "file": "auth-callback.component.css" +} \ No newline at end of file diff --git a/src/app/modules/home/main/main.component.css b/src/app/modules/home/main/main.component.css new file mode 100644 index 00000000..0a132066 --- /dev/null +++ b/src/app/modules/home/main/main.component.css @@ -0,0 +1 @@ +/* No CSS *//*# sourceMappingURL=main.component.css.map */ \ No newline at end of file diff --git a/src/app/modules/home/main/main.component.css.map b/src/app/modules/home/main/main.component.css.map new file mode 100644 index 00000000..b48e7fdf --- /dev/null +++ b/src/app/modules/home/main/main.component.css.map @@ -0,0 +1,9 @@ +{ + "version": 3, + "mappings": "", + "sources": [ + "main.component.scss" + ], + "names": [], + "file": "main.component.css" +} \ No newline at end of file diff --git a/src/app/modules/project/overview/overview.component.ts b/src/app/modules/project/overview/overview.component.ts index 57018738..0b5fd7b6 100644 --- a/src/app/modules/project/overview/overview.component.ts +++ b/src/app/modules/project/overview/overview.component.ts @@ -146,7 +146,7 @@ export class OverviewComponent implements OnInit, AfterViewInit { private paginationService: PaginationService, private internalSearchService: InternalSearchService, private formBuilder: FormBuilder, - private activatedRoute: ActivatedRoute, + private activatedRoute: ActivatedRoute, private seoService: SEOService, private modalService: BsModalService, private location: Location, diff --git a/src/app/modules/user/user-project/user-project.component.html b/src/app/modules/user/user-project/user-project.component.html index 0f72ab5f..8ff72233 100644 --- a/src/app/modules/user/user-project/user-project.component.html +++ b/src/app/modules/user/user-project/user-project.component.html @@ -16,3 +16,95 @@ If not, see https://www.gnu.org/licenses/lgpl-3.0.txt --> + + +
+ + +
+
+

My feed

+
+ + +
+
+ + +
+ + +
+
+ + +

+

There are no projects available.

+
+ +
+ + + + + + + + + + + + + + + + + + +
+
+
diff --git a/src/app/modules/user/user-project/user-project.component.scss b/src/app/modules/user/user-project/user-project.component.scss index e69de29b..a001e436 100644 --- a/src/app/modules/user/user-project/user-project.component.scss +++ b/src/app/modules/user/user-project/user-project.component.scss @@ -0,0 +1,201 @@ +/* + * + * Digital Excellence Copyright (C) 2020 Brend Smits + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You can find a copy of the GNU Lesser General Public License + * along with this program, in the LICENSE.md file in the root project directory. + * If not, see https://www.gnu.org/licenses/lgpl-3.0.txt + * + */ + @import "assets/styles/variables"; + + .projects-overview-wrapper { + padding: 0 5vw; + max-width: 1880px; + margin-left: auto; + margin-right: auto; + + .project-list-header { + width: 100%; + margin: 2em 0; + display: inline-flex; + justify-content: space-between; + align-content: center; + + h1 { + display: inline; + } + .list-view-toggle { + display: flex; + margin: auto 0 auto 20px; + gap: 12px; + flex-wrap: wrap; + justify-content: flex-end; + + @media only screen and (max-width: 720px) { + display: none; + } + + .container { + box-shadow: $box-shadow; + display: inline; + position: relative; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + padding: 0; + width: fit-content; + margin: 0; + height: fit-content; + } + + // Hide the default radio button + .container input[type="radio"] { + position: absolute; + opacity: 0; + cursor: pointer; + height: 0; + width: 0; + } + + // Create custom radio button + .checkmark { + height: 40px; + width: 40px; + padding: 10px; + border-radius: 5px; + background-color: $white; + color: $accent-color-red-primary; + display: flex; + justify-content: center; + align-items: center; + transition: transform $transition-short; + + &:hover { + transform: $transform-grow-big; + } + svg { + size: inherit; + width: 100%; + height: 100%; + margin: 0; + } + } + } + + // If the sibling input is checked + .container input[type="radio"]:checked ~ .checkmark { + color: $light-mode-grey-quaternary; + background: $accent-color-red-primary; + } + } + + + .project-list-wrapper { + width: 100%; + display: grid; + gap: 15px; + margin-bottom: 35px; + + &.grid { + gap: 25px; + grid-template-columns: repeat(auto-fill, minmax(310px, 1fr)); + } + } + + .pagination-div { + margin-top: 20px; + display: flex; + justify-content: center; + } + + .pagination-footer::ng-deep { + flex-wrap: wrap; + + .pagination-next, + .pagination-prev { + max-width: 35px; + overflow: hidden; + } + } + + .pagination-footer::ng-deep .page-link { + z-index: 1; + color: $light-mode-black; + height: 35px; + display: flex; + align-items: center; + } + + .pagination-footer::ng-deep .page-item.active .page-link { + border-color: $accent-color-red-primary; + background-color: $accent-color-red-primary !important; + color: #ffffff; + } + + .paginationDropDown { + width: 80px; + } + + .pagination-footer { + li { + height: 35px; + width: 35px; + } + a { + height: 35px; + width: 35px; + } + img { + width: 100%; + } + .chevron-right { + margin-top: 1px; + transform: rotateZ(270deg); + } + .chevron-left { + margin-top: 1px; + transform: rotateZ(90deg); + } + .disabled { + opacity: 0.3; + } + } + + .paginationDropDown { + width: 80px; + } + + .loading-circle { + color: $accent-color-red-primary; + } + } + + .projects-filter-wrapper { + min-width: 250px; + @media only screen and (min-width: 1000px) { + max-width: 300px; + } + height: 100vh; + position: sticky; + top: 0; + margin: -24px 24px -64px -24px; // override padding from parent element & footer + padding: 48px 36px; + background-color: white; + + .divider { + border-bottom: 1px solid $light-mode-grey-thertiary; + } + } + \ No newline at end of file diff --git a/src/app/modules/user/user-project/user-project.component.ts b/src/app/modules/user/user-project/user-project.component.ts index 177936b7..cf63b407 100644 --- a/src/app/modules/user/user-project/user-project.component.ts +++ b/src/app/modules/user/user-project/user-project.component.ts @@ -1,15 +1,85 @@ +/* + * Digital Excellence Copyright (C) 2020 Brend Smits + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You can find a copy of the GNU Lesser General Public License + * along with this program, in the LICENSE.md file in the root project directory. + * If not, see https://www.gnu.org/licenses/lgpl-3.0.txt + */ + import { Component, OnInit } from '@angular/core'; +import { SafeUrl } from '@angular/platform-browser'; +import { finalize } from 'rxjs/operators'; +import { Project } from 'src/app/models/domain/project'; +import { AuthService } from 'src/app/services/auth.service'; +import { FileRetrieverService } from 'src/app/services/file-retriever.service'; +import { UserService } from 'src/app/services/user.service'; +//import { RecommendationService } from 'src/app/services/recommendation.service'; +import { ProjectDetailModalUtility } from 'src/app/utils/project-detail-modal.util'; @Component({ - selector: 'app-user-project', + selector: 'user-project', templateUrl: './user-project.component.html', - styleUrls: ['./user-project.component.scss'] + styleUrls: ['./user-project.component.scss'], }) export class UserProjectComponent implements OnInit { - constructor() { } + public isAuthenticated: boolean; + + /** + * Array to receive and store the projects from the api. + */ + public userprojects: Project[] = []; + + /** + * Boolean to determine whether the component is loading the information from the api. + */ + public userprojectsLoading = true; + + constructor(private userService: UserService, + private fileRetrieverService: FileRetrieverService, + private modalUtility: ProjectDetailModalUtility, + private authService: AuthService) {} ngOnInit(): void { + this.authService.authNavStatus$.subscribe((status) => { + this.isAuthenticated = status; + if (status) { + this.userService.getProjectsFromUser() + .pipe(finalize(() => (this.userprojectsLoading = false))) + .subscribe((result) => { + this.userprojects = result; + this.userprojects.forEach(element => { + element.likeCount = element.likes.length; + }); + }); + } + }); } -} + /** +* Triggers on project click in the list. +* @param id project id. +* @param name project name +*/ + public onClickUserProject(id: number, name: string): void { + name = name.split(' ').join('-'); + this.modalUtility.openProjectModal(id, name, '/home'); + } + + /** + * Method to get the url of the icon of the project. This is retrieved + * from the file retriever service + */ + public getIconUrl(project: Project): SafeUrl { + return this.fileRetrieverService.getIconUrl(project.projectIcon); + } +} \ No newline at end of file diff --git a/src/app/services/user.service.ts b/src/app/services/user.service.ts index 7456bfe7..c058f3bc 100644 --- a/src/app/services/user.service.ts +++ b/src/app/services/user.service.ts @@ -22,6 +22,7 @@ import { User } from 'src/app/models/domain/user'; import { UserAdd } from 'src/app/models/resources/user-add'; import { HttpBaseService } from './http-base.service'; import { Observable } from 'rxjs'; +import { Project } from 'src/app/models/domain/project'; @Injectable({ providedIn: 'root', @@ -35,4 +36,8 @@ export class UserService extends HttpBaseService { public getCurrentUser(): Observable { return this.http.get(this.url); } + + public getProjectsFromUser(): Observable { + return this.http.get(`${this.url}`); + } } From 2c0b32a342118c3836c87acf84a9d11833fad9c4 Mon Sep 17 00:00:00 2001 From: Ruben Date: Fri, 11 Jun 2021 15:00:43 +0200 Subject: [PATCH 03/30] Updated endpoint for retrieving user projects --- src/app/services/user.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/services/user.service.ts b/src/app/services/user.service.ts index c058f3bc..ca7fc992 100644 --- a/src/app/services/user.service.ts +++ b/src/app/services/user.service.ts @@ -38,6 +38,6 @@ export class UserService extends HttpBaseService { } public getProjectsFromUser(): Observable { - return this.http.get(`${this.url}`); + return this.http.get(`${this.url}/projects`); } } From f1c10c89af4c55f8fc7d2bd2e53309dcf3c4c49d Mon Sep 17 00:00:00 2001 From: Ruben Date: Fri, 11 Jun 2021 15:01:11 +0200 Subject: [PATCH 04/30] Added missing method --- src/app/modules/user/user-project/user-project.component.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app/modules/user/user-project/user-project.component.ts b/src/app/modules/user/user-project/user-project.component.ts index cf63b407..59e2d477 100644 --- a/src/app/modules/user/user-project/user-project.component.ts +++ b/src/app/modules/user/user-project/user-project.component.ts @@ -82,4 +82,8 @@ export class UserProjectComponent implements OnInit { public getIconUrl(project: Project): SafeUrl { return this.fileRetrieverService.getIconUrl(project.projectIcon); } -} \ No newline at end of file + + public projectsEmpty(): boolean { + return this.userprojects.length < 1; + } +} From ff6f912c91b1112fb961aae5e142a861c4b36b3a Mon Sep 17 00:00:00 2001 From: Ruben Date: Fri, 11 Jun 2021 15:28:55 +0200 Subject: [PATCH 05/30] Imported missing dependencies --- .../user-project/user-project.component.html | 2 +- .../user-project/user-project.component.ts | 219 +++++++++++++++++- src/app/modules/user/user.module.ts | 8 +- 3 files changed, 226 insertions(+), 3 deletions(-) diff --git a/src/app/modules/user/user-project/user-project.component.html b/src/app/modules/user/user-project/user-project.component.html index 8ff72233..1bc66158 100644 --- a/src/app/modules/user/user-project/user-project.component.html +++ b/src/app/modules/user/user-project/user-project.component.html @@ -36,7 +36,7 @@ -->
- +
diff --git a/src/app/modules/user/user-project/user-project.component.ts b/src/app/modules/user/user-project/user-project.component.ts index 59e2d477..344229be 100644 --- a/src/app/modules/user/user-project/user-project.component.ts +++ b/src/app/modules/user/user-project/user-project.component.ts @@ -16,14 +16,28 @@ */ import { Component, OnInit } from '@angular/core'; +import { FormControl } from '@angular/forms'; import { SafeUrl } from '@angular/platform-browser'; +import { Router } from '@angular/router'; import { finalize } from 'rxjs/operators'; +import { SelectFormOption } from 'src/app/interfaces/select-form-option'; import { Project } from 'src/app/models/domain/project'; +import { ProjectCategory } from 'src/app/models/domain/projectCategory'; +import { SearchResultsResource } from 'src/app/models/resources/search-results'; import { AuthService } from 'src/app/services/auth.service'; import { FileRetrieverService } from 'src/app/services/file-retriever.service'; +import { InternalSearchService } from 'src/app/services/internal-search.service'; +import { PaginationService } from 'src/app/services/pagination.service'; import { UserService } from 'src/app/services/user.service'; //import { RecommendationService } from 'src/app/services/recommendation.service'; import { ProjectDetailModalUtility } from 'src/app/utils/project-detail-modal.util'; +import { InternalSearchQuery } from 'src/app/models/resources/internal-search-query'; +import { PageChangedEvent } from 'ngx-bootstrap/pagination'; +import { SEOService } from 'src/app/services/seo.service'; +import { Location } from '@angular/common'; +import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; +import { DetailsComponent } from '../../project/details/details.component'; +import { Subscription } from 'rxjs'; @Component({ selector: 'user-project', @@ -32,8 +46,54 @@ import { ProjectDetailModalUtility } from 'src/app/utils/project-detail-modal.ut }) export class UserProjectComponent implements OnInit { + public sortSelectOptions: SelectFormOption[] = [ + {value: 'updated,desc', viewValue: 'Updated (new-old)'}, + {value: 'updated,asc', viewValue: 'Updated (old-new)'}, + {value: 'name,asc', viewValue: 'Name (a-z)'}, + {value: 'name,desc', viewValue: 'Name (z-a)'}, + {value: 'created,desc', viewValue: 'Created (new-old)'}, + {value: 'created,asc', viewValue: 'Created (old-new)'}, + ]; + public isAuthenticated: boolean; + public projectsToDisplay: Project[] = []; + public searchControl: FormControl = null; + + public categories: ProjectCategory[]; + + private modalRef: BsModalRef; + private modalSubscriptions: Subscription[] = []; + + /** + * The number of projects that are on the platform + */ + public totalNrOfProjects = 0; + + /** + * Boolean to determine whether the component is loading the information from the api. + */ + public projectsLoading = true; + + /** + * Stores the response with the paginated projects etc. from the api. + */ + public paginationResponse: SearchResultsResource; + public showListView: boolean = false; + + public showPaginationFooter = true; + public currentPage; + /** + * Parameters for keeping track of the current internalSearch query values. + */ + private currentSearchInput: string; + private currentSortOptions: string = this.sortSelectOptions[0].value; + private currentSortType: string = this.currentSortOptions.split(',')[0]; + private currentSortDirection: string = this.currentSortOptions.split(',')[1]; + /** + * The amount of projects that will be displayed on a single page. + */ + public amountOfProjectsOnSinglePage = 12; /** * Array to receive and store the projects from the api. */ @@ -45,9 +105,15 @@ export class UserProjectComponent implements OnInit { public userprojectsLoading = true; constructor(private userService: UserService, + private router: Router, private fileRetrieverService: FileRetrieverService, private modalUtility: ProjectDetailModalUtility, - private authService: AuthService) {} + private authService: AuthService, + private internalSearchService: InternalSearchService, + private paginationService: PaginationService, + private seoService: SEOService, + private location: Location, + private modalService: BsModalService) {} ngOnInit(): void { this.authService.authNavStatus$.subscribe((status) => { @@ -75,6 +141,25 @@ export class UserProjectComponent implements OnInit { this.modalUtility.openProjectModal(id, name, '/home'); } + /** + * Triggers on project click in the list. + * @param event click event + * @param id project id. + * @param name project name + */ + public onClickProject(event: Event, id: number, name: string): void { + name = name.split(' ').join('-'); + + const clickedSection = event.target as Element; + + if (clickedSection.classList.contains('project-collaborators')) { + this.createProjectModal(id, 'collaborators'); + } else { + this.createProjectModal(id); + } + this.location.replaceState(`/project/details/${id}-${name}`); + } + /** * Method to get the url of the icon of the project. This is retrieved * from the file retriever service @@ -86,4 +171,136 @@ export class UserProjectComponent implements OnInit { public projectsEmpty(): boolean { return this.userprojects.length < 1; } + + /** + * Method that retrieves the page of the pagination footer when the user selects a new one. + * @param event holds the current page of the pagination footer, as well as the amount + * of projects that are being displayed on a single page. + */ + public pageChanged(event: PageChangedEvent): void { + this.currentPage = event.page; + this.onInternalQueryChange(); + } + + private onInternalQueryChange(): void { + const internalSearchQuery: InternalSearchQuery = { + query: this.currentSearchInput === '' ? null : this.currentSearchInput, + // If there is a search query, search on all pages + page: !this.currentSearchInput ? this.currentPage : null, + amountOnPage: this.amountOfProjectsOnSinglePage, + sortBy: this.currentSortType, + sortDirection: this.currentSortDirection, + categories: this.categories + .map(value => value.selected ? value.id : null) + .filter(value => value) + }; + + this.updateQueryParams(); + + if (internalSearchQuery.query == null) { + // No search query provided use projectService. + this.paginationService + .getProjectsPaginated(internalSearchQuery) + .pipe(finalize(() => (this.userprojectsLoading = false))) + .subscribe((result) => this.handleSearchAndProjectResponse(result)); + } else { + // Search query provided use searchService. + this.internalSearchService + .getSearchResultsPaginated(internalSearchQuery) + .pipe(finalize(() => (this.userprojectsLoading = false))) + .subscribe((result) => this.handleSearchAndProjectResponse(result)); + } + } + + private updateQueryParams() { + this.router.navigate( + [], + { + queryParams: { + query: this.searchControl.value, + sortOption: this.currentSortOptions, + pagination: this.amountOfProjectsOnSinglePage, + categories: JSON.stringify( + this.categories?.map(category => + category.selected ? category.id : null + ).filter(category => category) + ) + }, + queryParamsHandling: 'merge' + }); + } + + /** + * Method to handle the response of the call to the project or search service. + */ + private handleSearchAndProjectResponse(response: SearchResultsResource): void { + this.paginationResponse = response; + + this.userprojects = response.results; + this.projectsToDisplay = response.results; + this.totalNrOfProjects = response.totalCount; + + this.userprojects = response.results; + + if (this.userprojects.length < this.amountOfProjectsOnSinglePage && this.currentPage <= 1) { + this.showPaginationFooter = false; + } else { + this.showPaginationFooter = true; + } + } + + /** + * Method to open the modal for a projects detail + * @param projectId the id of the project that should be shown. + * @param activeTab Define the active tab + */ + private createProjectModal(projectId: number, activeTab: string = 'description') { + const initialState = { + projectId: projectId, + activeTab: activeTab + }; + if (projectId) { + this.modalRef = this.modalService.show(DetailsComponent, {animated: true, initialState}); + this.modalRef.setClass('project-modal'); + + this.modalRef.content.onLike.subscribe(isLiked => { + const projectIndexToUpdate = this.userprojects.findIndex(project => project.id === projectId); + if (isLiked) { + this.userprojects[projectIndexToUpdate].likeCount++; + this.userprojects[projectIndexToUpdate].userHasLikedProject = true; + } else { + this.userprojects[projectIndexToUpdate].likeCount--; + this.userprojects[projectIndexToUpdate].userHasLikedProject = false; + } + }); + + // Go back to home page after the modal is closed + this.modalSubscriptions.push( + this.modalService.onHide.subscribe(() => { + if (this.location.path().startsWith('/project/details')) { + const queryString = `query=${this.searchControl.value}` + + `&sortOption=${this.currentSortOptions}` + + `&pagination=${this.amountOfProjectsOnSinglePage}` + + `&page=${this.currentPage}` + + `&categories=${JSON.stringify(this.categories?.map( + category => category.selected ? category.id : null) + .filter(category => category) + )}`; + this.location.replaceState(`/project/overview/`, queryString); + this.updateSEOTags(); + this.onInternalQueryChange(); + } + } + )); + } + } + + /** + * Methods to update the title and description through the SEO service + */ + private updateSEOTags() { + // Updates meta and title tags + this.seoService.updateTitle('Project overview'); + this.seoService.updateDescription('Browse or search for specific projects or ideas within DeX'); + } } diff --git a/src/app/modules/user/user.module.ts b/src/app/modules/user/user.module.ts index ff66c245..9a31b2df 100644 --- a/src/app/modules/user/user.module.ts +++ b/src/app/modules/user/user.module.ts @@ -3,13 +3,19 @@ import { CommonModule } from '@angular/common'; import { UserRoutingModule } from './user-routing.module'; import { UserProjectComponent } from './user-project/user-project.component'; +import { PaginationModule } from 'ngx-bootstrap/pagination'; +import { ProjectModule } from '../project/project.module'; +import { FormsModule } from '@angular/forms'; @NgModule({ declarations: [UserProjectComponent], imports: [ CommonModule, - UserRoutingModule + UserRoutingModule, + PaginationModule.forRoot(), + ProjectModule, + FormsModule ] }) export class UserModule { } From 65040d030dbfb50c56eba3a3cd718359f1622465 Mon Sep 17 00:00:00 2001 From: Ruben Date: Fri, 11 Jun 2021 15:32:53 +0200 Subject: [PATCH 06/30] Updated projects to display --- src/app/modules/user/user-project/user-project.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/modules/user/user-project/user-project.component.ts b/src/app/modules/user/user-project/user-project.component.ts index 344229be..f89eb1e7 100644 --- a/src/app/modules/user/user-project/user-project.component.ts +++ b/src/app/modules/user/user-project/user-project.component.ts @@ -29,7 +29,6 @@ import { FileRetrieverService } from 'src/app/services/file-retriever.service'; import { InternalSearchService } from 'src/app/services/internal-search.service'; import { PaginationService } from 'src/app/services/pagination.service'; import { UserService } from 'src/app/services/user.service'; -//import { RecommendationService } from 'src/app/services/recommendation.service'; import { ProjectDetailModalUtility } from 'src/app/utils/project-detail-modal.util'; import { InternalSearchQuery } from 'src/app/models/resources/internal-search-query'; import { PageChangedEvent } from 'ngx-bootstrap/pagination'; @@ -126,6 +125,7 @@ export class UserProjectComponent implements OnInit { this.userprojects.forEach(element => { element.likeCount = element.likes.length; }); + this.projectsToDisplay = this.userprojects; }); } }); From 48042bf7daa4b5abf913c66ed490ca43acdf4544 Mon Sep 17 00:00:00 2001 From: macfleury-2000 Date: Mon, 14 Jun 2021 10:33:29 +0200 Subject: [PATCH 07/30] Added my projects button --- package.json | 2 +- src/app/components/app-layout/app-layout.component.html | 1 + src/app/components/app-layout/app-layout.component.scss | 1 + src/app/components/app-layout/app-layout.component.ts | 5 +++++ 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index caeddbf1..29a4a696 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ }, "devDependencies": { "@angular-devkit/build-angular": "^0.901.13", - "@angular/cli": "^9.1.13", + "@angular/cli": "^9.1.15", "@angular/compiler-cli": "^9.1.13", "@angular/language-service": "^9.1.13", "@types/jasmine": "^3.6.3", diff --git a/src/app/components/app-layout/app-layout.component.html b/src/app/components/app-layout/app-layout.component.html index ae48e873..78a54cb2 100644 --- a/src/app/components/app-layout/app-layout.component.html +++ b/src/app/components/app-layout/app-layout.component.html @@ -53,6 +53,7 @@
diff --git a/src/app/components/app-layout/app-layout.component.scss b/src/app/components/app-layout/app-layout.component.scss index dc56cfd2..7fe54a66 100644 --- a/src/app/components/app-layout/app-layout.component.scss +++ b/src/app/components/app-layout/app-layout.component.scss @@ -188,6 +188,7 @@ below each other */ .profile-dropdown { + z-index: 9; @include media-breakpoint-down(sm) { flex-direction: column; } diff --git a/src/app/components/app-layout/app-layout.component.ts b/src/app/components/app-layout/app-layout.component.ts index f1c279c4..125d36b7 100644 --- a/src/app/components/app-layout/app-layout.component.ts +++ b/src/app/components/app-layout/app-layout.component.ts @@ -120,6 +120,11 @@ export class AppLayoutComponent implements OnInit { this.displayBetaBanner = true; } + + public viewUserProjects() { + this.router.navigate(['user/projects']); + } + /** * Method which triggers when the user clicks on the burger menu in the header. * Toggles the navbar visibility From fe3d68b03fbda228f51f133ac966b55656e9a9f4 Mon Sep 17 00:00:00 2001 From: macfleury-2000 Date: Mon, 14 Jun 2021 12:09:07 +0200 Subject: [PATCH 08/30] First primary version --- src/app/components/app-layout/app-layout.component.html | 2 +- src/app/modules/project/overview/project/project.component.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/components/app-layout/app-layout.component.html b/src/app/components/app-layout/app-layout.component.html index 78a54cb2..2aaad2c2 100644 --- a/src/app/components/app-layout/app-layout.component.html +++ b/src/app/components/app-layout/app-layout.component.html @@ -33,7 +33,7 @@ +
From aa1f7a8e67546b5ee1d106923225808aa58741f5 Mon Sep 17 00:00:00 2001 From: macfleury-2000 Date: Mon, 14 Jun 2021 12:11:34 +0200 Subject: [PATCH 09/30] first primary version --- .../app-layout/app-layout.component.ts | 2 +- .../user-project/user-project.component.html | 20 +++++++ .../user-project/user-project.component.scss | 59 +++++++++++++++++++ .../user-project/user-project.component.ts | 8 +++ 4 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/app/components/app-layout/app-layout.component.ts b/src/app/components/app-layout/app-layout.component.ts index 125d36b7..fd7d2b41 100644 --- a/src/app/components/app-layout/app-layout.component.ts +++ b/src/app/components/app-layout/app-layout.component.ts @@ -23,7 +23,7 @@ import { AlertService } from 'src/app/services/alert.service'; import { NavigationEnd, NavigationStart, Router } from '@angular/router'; /** - * Component used to display the basic layout of the application. + * Component used to display the basic layout of the application. */ @Component({ selector: 'app-layout', diff --git a/src/app/modules/user/user-project/user-project.component.html b/src/app/modules/user/user-project/user-project.component.html index 1bc66158..9ba56a8b 100644 --- a/src/app/modules/user/user-project/user-project.component.html +++ b/src/app/modules/user/user-project/user-project.component.html @@ -41,6 +41,7 @@

My feed

+
+
+ +
+

{{ name }}

+

Projects: {{ userprojects.length }}

+
+
+ +
+
+ +
My projects
+
+
+ +
Collaborated projects
+
+
+
{ + this.isAuthenticated = status; + this.name = this.authService.name; + }); + this.authService.authNavStatus$.subscribe((status) => { this.isAuthenticated = status; if (status) { From 183b675996b53c2f6d78cde423ab62a1b3afc295 Mon Sep 17 00:00:00 2001 From: macfleury-2000 Date: Mon, 14 Jun 2021 15:02:22 +0200 Subject: [PATCH 10/30] added needed functions --- .../user-project/user-project.component.html | 11 +- .../user-project/user-project.component.ts | 592 ++++++++++++------ src/app/modules/user/user.module.ts | 11 +- 3 files changed, 404 insertions(+), 210 deletions(-) diff --git a/src/app/modules/user/user-project/user-project.component.html b/src/app/modules/user/user-project/user-project.component.html index 9ba56a8b..d99ad2ec 100644 --- a/src/app/modules/user/user-project/user-project.component.html +++ b/src/app/modules/user/user-project/user-project.component.html @@ -71,14 +71,21 @@

{{ name }}

-
+ +

Pagination

+ +
diff --git a/src/app/modules/user/user-project/user-project.component.ts b/src/app/modules/user/user-project/user-project.component.ts index c50079d4..e153b992 100644 --- a/src/app/modules/user/user-project/user-project.component.ts +++ b/src/app/modules/user/user-project/user-project.component.ts @@ -15,11 +15,10 @@ * If not, see https://www.gnu.org/licenses/lgpl-3.0.txt */ -import { Component, OnInit } from '@angular/core'; -import { FormControl } from '@angular/forms'; +import { AfterViewInit, Component, OnInit } from '@angular/core'; import { SafeUrl } from '@angular/platform-browser'; -import { Router } from '@angular/router'; -import { finalize } from 'rxjs/operators'; +import { ActivatedRoute, Router } from '@angular/router'; +import { debounceTime, finalize } from 'rxjs/operators'; import { SelectFormOption } from 'src/app/interfaces/select-form-option'; import { Project } from 'src/app/models/domain/project'; import { ProjectCategory } from 'src/app/models/domain/projectCategory'; @@ -37,6 +36,10 @@ import { Location } from '@angular/common'; import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; import { DetailsComponent } from '../../project/details/details.component'; import { Subscription } from 'rxjs'; +import { FormBuilder, FormControl } from '@angular/forms'; +import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject'; +import { environment } from 'src/environments/environment'; +import { CategoryService } from 'src/app/services/category.service'; @Component({ selector: 'user-project', @@ -56,12 +59,19 @@ export class UserProjectComponent implements OnInit { public isAuthenticated: boolean; public projectsToDisplay: Project[] = []; - public searchControl: FormControl = null; +; + + + + /** + * FormControl for getting the input. + */ + public sortOptionControl: FormControl = null; + public paginationOptionControl: FormControl = null; + public searchControl: FormControl = null public categories: ProjectCategory[]; - private modalRef: BsModalRef; - private modalSubscriptions: Subscription[] = []; public name: string; public photo : File; @@ -85,13 +95,30 @@ export class UserProjectComponent implements OnInit { public showPaginationFooter = true; public currentPage; + + /** + * The possible pagination options for the dropdown + */ + public paginationDropDownOptions = [ + {id: 0, amountOnPage: 12}, + {id: 1, amountOnPage: 24}, + {id: 2, amountOnPage: 36}, + ]; + + /** + * Default pagination option for the dropdown + */ + public defaultPaginationOption = { + id: 0, + amountOnPage: 12 + }; + + /** * Parameters for keeping track of the current internalSearch query values. */ - private currentSearchInput: string; private currentSortOptions: string = this.sortSelectOptions[0].value; - private currentSortType: string = this.currentSortOptions.split(',')[0]; - private currentSortDirection: string = this.currentSortOptions.split(',')[1]; + /** * The amount of projects that will be displayed on a single page. */ @@ -106,8 +133,41 @@ export class UserProjectComponent implements OnInit { */ public userprojectsLoading = true; + private searchSubject = new BehaviorSubject(null); + + /** + * Array to receive and store the projects from the api. + */ + public projects: Project[] = []; + public projectsTotal: Project[] = []; + + public displaySearchElements = false; + + + /** + * Project parameter gets updated per project detail modal + */ + public currentProject: Project = null; + + /** + * Parameters for keeping track of the current internalSearch query values. + */ + private currentSearchInput: string; + private currentSortType: string = this.currentSortOptions.split(',')[0]; + private currentSortDirection: string = this.currentSortOptions.split(',')[1]; + + /** + * Property to indicate whether the project is loading. + */ + private projectLoading = true; + + + private modalRef: BsModalRef; + private modalSubscriptions: Subscription[] = []; + + constructor(private userService: UserService, - private router: Router, + private router: Router, private fileRetrieverService: FileRetrieverService, private modalUtility: ProjectDetailModalUtility, private authService: AuthService, @@ -115,200 +175,322 @@ export class UserProjectComponent implements OnInit { private paginationService: PaginationService, private seoService: SEOService, private location: Location, - private modalService: BsModalService) {} - - ngOnInit(): void { - this.subscription = this.authService.authNavStatus$.subscribe((status) => { - this.isAuthenticated = status; - this.name = this.authService.name; - }); - - this.authService.authNavStatus$.subscribe((status) => { - this.isAuthenticated = status; - if (status) { - this.userService.getProjectsFromUser() - .pipe(finalize(() => (this.userprojectsLoading = false))) - .subscribe((result) => { - this.userprojects = result; - this.userprojects.forEach(element => { - element.likeCount = element.likes.length; - }); - this.projectsToDisplay = this.userprojects; - }); - } - }); - } - - /** -* Triggers on project click in the list. -* @param id project id. -* @param name project name -*/ - public onClickUserProject(id: number, name: string): void { - name = name.split(' ').join('-'); - this.modalUtility.openProjectModal(id, name, '/home'); - } - - /** - * Triggers on project click in the list. - * @param event click event - * @param id project id. - * @param name project name - */ - public onClickProject(event: Event, id: number, name: string): void { - name = name.split(' ').join('-'); - - const clickedSection = event.target as Element; - - if (clickedSection.classList.contains('project-collaborators')) { - this.createProjectModal(id, 'collaborators'); - } else { - this.createProjectModal(id); - } - this.location.replaceState(`/project/details/${id}-${name}`); - } - - /** - * Method to get the url of the icon of the project. This is retrieved - * from the file retriever service - */ - public getIconUrl(project: Project): SafeUrl { - return this.fileRetrieverService.getIconUrl(project.projectIcon); - } - - public projectsEmpty(): boolean { - return this.userprojects.length < 1; - } - - /** - * Method that retrieves the page of the pagination footer when the user selects a new one. - * @param event holds the current page of the pagination footer, as well as the amount - * of projects that are being displayed on a single page. - */ - public pageChanged(event: PageChangedEvent): void { - this.currentPage = event.page; - this.onInternalQueryChange(); - } - - private onInternalQueryChange(): void { - const internalSearchQuery: InternalSearchQuery = { - query: this.currentSearchInput === '' ? null : this.currentSearchInput, - // If there is a search query, search on all pages - page: !this.currentSearchInput ? this.currentPage : null, - amountOnPage: this.amountOfProjectsOnSinglePage, - sortBy: this.currentSortType, - sortDirection: this.currentSortDirection, - categories: this.categories - .map(value => value.selected ? value.id : null) - .filter(value => value) - }; - - this.updateQueryParams(); - - if (internalSearchQuery.query == null) { - // No search query provided use projectService. - this.paginationService - .getProjectsPaginated(internalSearchQuery) - .pipe(finalize(() => (this.userprojectsLoading = false))) - .subscribe((result) => this.handleSearchAndProjectResponse(result)); - } else { - // Search query provided use searchService. - this.internalSearchService - .getSearchResultsPaginated(internalSearchQuery) - .pipe(finalize(() => (this.userprojectsLoading = false))) - .subscribe((result) => this.handleSearchAndProjectResponse(result)); - } - } - - private updateQueryParams() { - this.router.navigate( - [], - { - queryParams: { - query: this.searchControl.value, - sortOption: this.currentSortOptions, - pagination: this.amountOfProjectsOnSinglePage, - categories: JSON.stringify( - this.categories?.map(category => - category.selected ? category.id : null - ).filter(category => category) - ) - }, - queryParamsHandling: 'merge' - }); - } - - /** - * Method to handle the response of the call to the project or search service. - */ - private handleSearchAndProjectResponse(response: SearchResultsResource): void { - this.paginationResponse = response; - - this.userprojects = response.results; - this.projectsToDisplay = response.results; - this.totalNrOfProjects = response.totalCount; - - this.userprojects = response.results; - - if (this.userprojects.length < this.amountOfProjectsOnSinglePage && this.currentPage <= 1) { - this.showPaginationFooter = false; - } else { - this.showPaginationFooter = true; - } - } - - /** - * Method to open the modal for a projects detail - * @param projectId the id of the project that should be shown. - * @param activeTab Define the active tab - */ - private createProjectModal(projectId: number, activeTab: string = 'description') { - const initialState = { - projectId: projectId, - activeTab: activeTab - }; - if (projectId) { - this.modalRef = this.modalService.show(DetailsComponent, {animated: true, initialState}); - this.modalRef.setClass('project-modal'); - - this.modalRef.content.onLike.subscribe(isLiked => { - const projectIndexToUpdate = this.userprojects.findIndex(project => project.id === projectId); - if (isLiked) { - this.userprojects[projectIndexToUpdate].likeCount++; - this.userprojects[projectIndexToUpdate].userHasLikedProject = true; - } else { - this.userprojects[projectIndexToUpdate].likeCount--; - this.userprojects[projectIndexToUpdate].userHasLikedProject = false; - } - }); - - // Go back to home page after the modal is closed - this.modalSubscriptions.push( - this.modalService.onHide.subscribe(() => { - if (this.location.path().startsWith('/project/details')) { - const queryString = `query=${this.searchControl.value}` - + `&sortOption=${this.currentSortOptions}` - + `&pagination=${this.amountOfProjectsOnSinglePage}` - + `&page=${this.currentPage}` - + `&categories=${JSON.stringify(this.categories?.map( - category => category.selected ? category.id : null) - .filter(category => category) - )}`; - this.location.replaceState(`/project/overview/`, queryString); - this.updateSEOTags(); + private modalService: BsModalService, + private formBuilder: FormBuilder, + private activatedRoute: ActivatedRoute, + private categoryService: CategoryService, + private route: ActivatedRoute) { + this.searchControl = new FormControl(''); + this.sortOptionControl = new FormControl(this.sortSelectOptions); + this.paginationOptionControl = new FormControl(this.paginationDropDownOptions[0]); + + } + + ngOnInit(): void { + // Subscribe to search subject to debounce the input and afterwards searchAndFilter. + this.searchSubject + .pipe( + debounceTime(500) + ) + .subscribe((result) => { + if (!result) { + return; + } this.onInternalQueryChange(); + }); + + this.searchControl.valueChanges.subscribe((value) => this.onSearchInputValueChange(value)); + + this.updateSEOTags(); + } + + ngAfterViewInit() { + this.categoryService.getAll().subscribe(categories => { + this.categories = categories; + this.processQueryParams(); + }); + + this.activatedRoute.params.subscribe(params => { + const projectId = params.id?.split('-')[0]; + this.createProjectModal(projectId); + }); + } + + public onCategoryClick(category): void { + this.categories = this.categories.map(cat => ( + cat.name === category.name + ? {...cat, selected: !category.selected} + : {...cat} + )); + } + + /** + * Method which triggers when the serach input receives a key up. + * Updates the search subject with the query. + * @param $event the event containing the info of the keyboard press. + */ + public onSearchInputValueChange(value: string): void { + // Do nothing if input did not change. + if (this.currentSearchInput === value) { + return; + } + + // Do nothing if the input contains only spaces or line breaks AND the value is not already empty. + // Indicating that the search was cleared and a new request should be made. + if (value !== '' && !value.replace(/\s/g, '').length) { + return; + } + + this.currentSearchInput = value; + this.searchSubject.next(value); + } + + /** + * Checks whether there are any projects + */ + public projectsEmpty(): boolean { + return this.projects.length < 1; + } + + /** + * Triggers on project click in the list. + * @param event click event + * @param id project id. + * @param name project name + */ + public onClickProject(event: Event, id: number, name: string): void { + name = name.split(' ').join('-'); + + const clickedSection = event.target as Element; + + if (clickedSection.classList.contains('project-collaborators')) { + this.createProjectModal(id, 'collaborators'); + } else { + this.createProjectModal(id); + } + this.location.replaceState(`/project/details/${id}-${name}`); + } + + /** + * Method that retrieves the page of the pagination footer when the user selects a new one. + * @param event holds the current page of the pagination footer, as well as the amount + * of projects that are being displayed on a single page. + */ + public pageChanged(event: PageChangedEvent): void { + this.currentPage = event.page; + this.onInternalQueryChange(); + } + + /** + * Method that retrieves the value that has changed from the pagination dropdown in the accordion, + * and based on that value retrieves the paginated projects with the right parameters. + * @param $event the identifier of the selected value. + */ + public onPaginationChange() { + this.amountOfProjectsOnSinglePage = this.paginationOptionControl.value.amountOnPage; + if (this.amountOfProjectsOnSinglePage === this.paginationResponse.totalCount) { + this.currentPage = 1; + } + this.onInternalQueryChange(); + } + + /** + * Method to handle value changes of the sort form. + * @param value the value of the form. + */ + public onSortFormValueChange(): void { + if (!this.sortOptionControl.value) { + return; + } + this.currentSortType = this.sortOptionControl.value.value.split(',')[0]; + this.currentSortDirection = this.sortOptionControl.value.value.split(',')[1]; + this.onInternalQueryChange(); + } + + public onCategoryChange(categoryId: number): void { + this.categories = this.categories.map(category => + category.id === categoryId + ? {...category, selected: !category.selected} + : category); + this.onInternalQueryChange(); + } + + /** + * Method to build the new internal search query when any of it params have changed. + * Calls the projectService or searchService based on the value of the query. + */ + private onInternalQueryChange(): void { + const internalSearchQuery: InternalSearchQuery = { + query: this.currentSearchInput === '' ? null : this.currentSearchInput, + // If there is a search query, search on all pages + page: !this.currentSearchInput ? this.currentPage : null, + amountOnPage: this.amountOfProjectsOnSinglePage, + sortBy: this.currentSortType, + sortDirection: this.currentSortDirection, + categories: this.categories + .map(value => value.selected ? value.id : null) + .filter(value => value) + }; + + this.updateQueryParams(); + + if (internalSearchQuery.query == null) { + // No search query provided use projectService. + this.paginationService + .getProjectsPaginated(internalSearchQuery) + .pipe(finalize(() => (this.projectsLoading = false))) + .subscribe((result) => this.handleSearchAndProjectResponse(result)); + } else { + // Search query provided use searchService. + this.internalSearchService + .getSearchResultsPaginated(internalSearchQuery) + .pipe(finalize(() => (this.projectsLoading = false))) + .subscribe((result) => this.handleSearchAndProjectResponse(result)); + } + } + + /** + * Method to handle the response of the call to the project or search service. + */ + private handleSearchAndProjectResponse(response: SearchResultsResource): void { + this.paginationResponse = response; + + this.projects = response.results; + this.projectsToDisplay = response.results; + this.totalNrOfProjects = response.totalCount; + + if (this.projects.length < this.amountOfProjectsOnSinglePage && this.currentPage <= 1) { + this.showPaginationFooter = false; + } else { + this.showPaginationFooter = true; + } + } + + /** + * Method to open the modal for a projects detail + * @param projectId the id of the project that should be shown. + * @param activeTab Define the active tab + */ + private createProjectModal(projectId: number, activeTab: string = 'description') { + const initialState = { + projectId: projectId, + activeTab: activeTab + }; + if (projectId) { + this.modalRef = this.modalService.show(DetailsComponent, {animated: true, initialState}); + this.modalRef.setClass('project-modal'); + + this.modalRef.content.onLike.subscribe(isLiked => { + const projectIndexToUpdate = this.projects.findIndex(project => project.id === projectId); + if (isLiked) { + this.projects[projectIndexToUpdate].likeCount++; + this.projects[projectIndexToUpdate].userHasLikedProject = true; + } else { + this.projects[projectIndexToUpdate].likeCount--; + this.projects[projectIndexToUpdate].userHasLikedProject = false; } + }); + + // Go back to home page after the modal is closed + this.modalSubscriptions.push( + this.modalService.onHide.subscribe(() => { + if (this.location.path().startsWith('/project/details')) { + const queryString = `query=${this.searchControl.value}` + + `&sortOption=${this.currentSortOptions}` + + `&pagination=${this.amountOfProjectsOnSinglePage}` + + `&page=${this.currentPage}` + + `&categories=${JSON.stringify(this.categories?.map( + category => category.selected ? category.id : null) + .filter(category => category) + )}`; + this.location.replaceState(`/project/overview/`, queryString); + this.updateSEOTags(); + this.onInternalQueryChange(); + } + } + )); + } + } + + private updateQueryParams() { + this.router.navigate( + [], + { + queryParams: { + query: this.searchControl.value, + sortOption: this.currentSortOptions, + pagination: this.amountOfProjectsOnSinglePage, + categories: JSON.stringify( + this.categories?.map(category => + category.selected ? category.id : null + ).filter(category => category) + ) + }, + queryParamsHandling: 'merge' + }); + } + + private processQueryParams() { + this.route.queryParams.subscribe(({query, categories: selectedCategories, sortOption, pagination}) => { + if (query !== 'null' && query !== 'undefined') { + this.searchControl.setValue(query); } - )); - } - } - - /** - * Methods to update the title and description through the SEO service - */ - private updateSEOTags() { - // Updates meta and title tags - this.seoService.updateTitle('Project overview'); - this.seoService.updateDescription('Browse or search for specific projects or ideas within DeX'); - } -} + + if (selectedCategories) { + selectedCategories = JSON.parse(selectedCategories); + if (selectedCategories.count > 0) { + this.categories = this.categories?.map(category => { + return { + ...category, + selected: selectedCategories.contains(category.id) + }; + }); + } + } + + if (sortOption) { + this.currentSortOptions = sortOption; + this.sortOptionControl.setValue(this.sortSelectOptions.find(option => option.value === sortOption)); + } + + if (pagination) { + const parsed = this.paginationDropDownOptions.find(option => + option.amountOnPage === parseInt(pagination, 10)); + + this.paginationOptionControl.setValue(parsed ? parsed : 12); + this.amountOfProjectsOnSinglePage = parsed ? parsed.amountOnPage : 12; + } + + this.onInternalQueryChange(); + }); + } + + /** + * Methods to update the title and description through the SEO service + */ + private updateSEOTags() { + // Updates meta and title tags + this.seoService.updateTitle('Project overview'); + this.seoService.updateDescription('Browse or search for specific projects or ideas within DeX'); + } + + /** + * Method to make tags change appearance on clicking. + * further implementation is still pending. + */ + public tagClicked(event) { + if (event.target.className === 'tag clicked') { + event.target.className = 'tag'; + } else { + event.target.className = 'tag clicked'; + } + } + + /** + * Method to display the tags based on the environment variable. + * Tags should be hidden in production for now until further implementation is finished. + */ + public displayTags(): boolean { + return !environment.production; + } + } \ No newline at end of file diff --git a/src/app/modules/user/user.module.ts b/src/app/modules/user/user.module.ts index 9a31b2df..dddc9809 100644 --- a/src/app/modules/user/user.module.ts +++ b/src/app/modules/user/user.module.ts @@ -5,17 +5,22 @@ import { UserRoutingModule } from './user-routing.module'; import { UserProjectComponent } from './user-project/user-project.component'; import { PaginationModule } from 'ngx-bootstrap/pagination'; import { ProjectModule } from '../project/project.module'; -import { FormsModule } from '@angular/forms'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; @NgModule({ - declarations: [UserProjectComponent], + declarations: [ + UserProjectComponent + ], imports: [ CommonModule, UserRoutingModule, PaginationModule.forRoot(), ProjectModule, - FormsModule + FormsModule, + CommonModule, + FormsModule, + ReactiveFormsModule, ] }) export class UserModule { } From 8796a7524ba885e2f90f5f80b55a3cce01904b11 Mon Sep 17 00:00:00 2001 From: macfleury-2000 Date: Mon, 14 Jun 2021 15:43:54 +0200 Subject: [PATCH 11/30] added another missing function --- .../user-project/user-project.component.ts | 55 +++++++++++++++---- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/src/app/modules/user/user-project/user-project.component.ts b/src/app/modules/user/user-project/user-project.component.ts index e153b992..9512fef1 100644 --- a/src/app/modules/user/user-project/user-project.component.ts +++ b/src/app/modules/user/user-project/user-project.component.ts @@ -138,8 +138,8 @@ export class UserProjectComponent implements OnInit { /** * Array to receive and store the projects from the api. */ - public projects: Project[] = []; - public projectsTotal: Project[] = []; + // public projects: Project[] = []; + // public projectsTotal: Project[] = []; public displaySearchElements = false; @@ -187,6 +187,26 @@ export class UserProjectComponent implements OnInit { } ngOnInit(): void { + this.subscription = this.authService.authNavStatus$.subscribe((status) => { + this.isAuthenticated = status; + this.name = this.authService.name; + }); + + this.authService.authNavStatus$.subscribe((status) => { + this.isAuthenticated = status; + if (status) { + this.userService.getProjectsFromUser() + .pipe(finalize(() => (this.userprojectsLoading = false))) + .subscribe((result) => { + this.userprojects = result; + this.userprojects.forEach(element => { + element.likeCount = element.likes.length; + }); + // this.projectsToDisplay = this.userprojects; + }); + } + }); + // Subscribe to search subject to debounce the input and afterwards searchAndFilter. this.searchSubject .pipe( @@ -215,6 +235,10 @@ export class UserProjectComponent implements OnInit { this.createProjectModal(projectId); }); } + public onClickUserProject(id: number, name: string): void { + name = name.split(' ').join('-'); + this.modalUtility.openProjectModal(id, name, '/home'); + } public onCategoryClick(category): void { this.categories = this.categories.map(cat => ( @@ -249,7 +273,7 @@ export class UserProjectComponent implements OnInit { * Checks whether there are any projects */ public projectsEmpty(): boolean { - return this.projects.length < 1; + return this.userprojects.length < 1; } /** @@ -270,6 +294,13 @@ export class UserProjectComponent implements OnInit { } this.location.replaceState(`/project/details/${id}-${name}`); } + /** + * Method to get the url of the icon of the project. This is retrieved + * from the file retriever service + */ + public getIconUrl(project: Project): SafeUrl { + return this.fileRetrieverService.getIconUrl(project.projectIcon); + } /** * Method that retrieves the page of the pagination footer when the user selects a new one. @@ -338,13 +369,13 @@ export class UserProjectComponent implements OnInit { // No search query provided use projectService. this.paginationService .getProjectsPaginated(internalSearchQuery) - .pipe(finalize(() => (this.projectsLoading = false))) + .pipe(finalize(() => (this.userprojectsLoading = false))) .subscribe((result) => this.handleSearchAndProjectResponse(result)); } else { // Search query provided use searchService. this.internalSearchService .getSearchResultsPaginated(internalSearchQuery) - .pipe(finalize(() => (this.projectsLoading = false))) + .pipe(finalize(() => (this.userprojectsLoading = false))) .subscribe((result) => this.handleSearchAndProjectResponse(result)); } } @@ -355,11 +386,11 @@ export class UserProjectComponent implements OnInit { private handleSearchAndProjectResponse(response: SearchResultsResource): void { this.paginationResponse = response; - this.projects = response.results; + this.userprojects = response.results; this.projectsToDisplay = response.results; this.totalNrOfProjects = response.totalCount; - if (this.projects.length < this.amountOfProjectsOnSinglePage && this.currentPage <= 1) { + if (this.userprojects.length < this.amountOfProjectsOnSinglePage && this.currentPage <= 1) { this.showPaginationFooter = false; } else { this.showPaginationFooter = true; @@ -381,13 +412,13 @@ export class UserProjectComponent implements OnInit { this.modalRef.setClass('project-modal'); this.modalRef.content.onLike.subscribe(isLiked => { - const projectIndexToUpdate = this.projects.findIndex(project => project.id === projectId); + const projectIndexToUpdate = this.userprojects.findIndex(project => project.id === projectId); if (isLiked) { - this.projects[projectIndexToUpdate].likeCount++; - this.projects[projectIndexToUpdate].userHasLikedProject = true; + this.userprojects[projectIndexToUpdate].likeCount++; + this.userprojects[projectIndexToUpdate].userHasLikedProject = true; } else { - this.projects[projectIndexToUpdate].likeCount--; - this.projects[projectIndexToUpdate].userHasLikedProject = false; + this.userprojects[projectIndexToUpdate].likeCount--; + this.userprojects[projectIndexToUpdate].userHasLikedProject = false; } }); From 09a81e1e63df20cf6882ecc7ffba879da946b5ad Mon Sep 17 00:00:00 2001 From: macfleury-2000 Date: Thu, 17 Jun 2021 10:15:13 +0200 Subject: [PATCH 12/30] Finished design --- .../user/user-project/user-project.component.html | 10 +++++----- .../user/user-project/user-project.component.scss | 12 ++++++++++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/app/modules/user/user-project/user-project.component.html b/src/app/modules/user/user-project/user-project.component.html index d99ad2ec..30f124bf 100644 --- a/src/app/modules/user/user-project/user-project.component.html +++ b/src/app/modules/user/user-project/user-project.component.html @@ -40,7 +40,7 @@
-

My feed

+

My projects

- +

{{ name }}

Projects: {{ userprojects.length }}

-
+

Pagination

- +
-
+
diff --git a/src/app/modules/user/user-project/user-project.component.scss b/src/app/modules/user/user-project/user-project.component.scss index 2aa132de..d66d3274 100644 --- a/src/app/modules/user/user-project/user-project.component.scss +++ b/src/app/modules/user/user-project/user-project.component.scss @@ -74,8 +74,16 @@ } } - - + .option-select{ + width: 200px; + display: inline-block; + margin: 10px 0 40px 0; + padding-left: 5px; + height: 30px; + background-color: #ffffff; + border: 0; + border-radius: 5px; + } .projects-overview-wrapper { padding: 0 5vw; From 6bb6f6741bd65f3291dd88917eb7b368d4c4b290 Mon Sep 17 00:00:00 2001 From: macfleury-2000 Date: Thu, 17 Jun 2021 10:47:14 +0200 Subject: [PATCH 13/30] Revert "Added my projects button" This reverts commit 48042bf7daa4b5abf913c66ed490ca43acdf4544. --- package.json | 2 +- src/app/components/app-layout/app-layout.component.html | 1 - src/app/components/app-layout/app-layout.component.scss | 1 - src/app/components/app-layout/app-layout.component.ts | 5 ----- 4 files changed, 1 insertion(+), 8 deletions(-) diff --git a/package.json b/package.json index 29a4a696..caeddbf1 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ }, "devDependencies": { "@angular-devkit/build-angular": "^0.901.13", - "@angular/cli": "^9.1.15", + "@angular/cli": "^9.1.13", "@angular/compiler-cli": "^9.1.13", "@angular/language-service": "^9.1.13", "@types/jasmine": "^3.6.3", diff --git a/src/app/components/app-layout/app-layout.component.html b/src/app/components/app-layout/app-layout.component.html index 2aaad2c2..d6613be0 100644 --- a/src/app/components/app-layout/app-layout.component.html +++ b/src/app/components/app-layout/app-layout.component.html @@ -53,7 +53,6 @@
diff --git a/src/app/components/app-layout/app-layout.component.scss b/src/app/components/app-layout/app-layout.component.scss index 7fe54a66..dc56cfd2 100644 --- a/src/app/components/app-layout/app-layout.component.scss +++ b/src/app/components/app-layout/app-layout.component.scss @@ -188,7 +188,6 @@ below each other */ .profile-dropdown { - z-index: 9; @include media-breakpoint-down(sm) { flex-direction: column; } diff --git a/src/app/components/app-layout/app-layout.component.ts b/src/app/components/app-layout/app-layout.component.ts index fd7d2b41..e8096d78 100644 --- a/src/app/components/app-layout/app-layout.component.ts +++ b/src/app/components/app-layout/app-layout.component.ts @@ -120,11 +120,6 @@ export class AppLayoutComponent implements OnInit { this.displayBetaBanner = true; } - - public viewUserProjects() { - this.router.navigate(['user/projects']); - } - /** * Method which triggers when the user clicks on the burger menu in the header. * Toggles the navbar visibility From 05a7fa4e3eb6cf8309bd8b2a9a07386e32bb0829 Mon Sep 17 00:00:00 2001 From: macfleury-2000 Date: Thu, 17 Jun 2021 10:48:17 +0200 Subject: [PATCH 14/30] Revert "Revert "Added my projects button"" This reverts commit 6bb6f6741bd65f3291dd88917eb7b368d4c4b290. --- package.json | 2 +- src/app/components/app-layout/app-layout.component.html | 1 + src/app/components/app-layout/app-layout.component.scss | 1 + src/app/components/app-layout/app-layout.component.ts | 5 +++++ 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index caeddbf1..29a4a696 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ }, "devDependencies": { "@angular-devkit/build-angular": "^0.901.13", - "@angular/cli": "^9.1.13", + "@angular/cli": "^9.1.15", "@angular/compiler-cli": "^9.1.13", "@angular/language-service": "^9.1.13", "@types/jasmine": "^3.6.3", diff --git a/src/app/components/app-layout/app-layout.component.html b/src/app/components/app-layout/app-layout.component.html index d6613be0..2aaad2c2 100644 --- a/src/app/components/app-layout/app-layout.component.html +++ b/src/app/components/app-layout/app-layout.component.html @@ -53,6 +53,7 @@
diff --git a/src/app/components/app-layout/app-layout.component.scss b/src/app/components/app-layout/app-layout.component.scss index dc56cfd2..7fe54a66 100644 --- a/src/app/components/app-layout/app-layout.component.scss +++ b/src/app/components/app-layout/app-layout.component.scss @@ -188,6 +188,7 @@ below each other */ .profile-dropdown { + z-index: 9; @include media-breakpoint-down(sm) { flex-direction: column; } diff --git a/src/app/components/app-layout/app-layout.component.ts b/src/app/components/app-layout/app-layout.component.ts index e8096d78..fd7d2b41 100644 --- a/src/app/components/app-layout/app-layout.component.ts +++ b/src/app/components/app-layout/app-layout.component.ts @@ -120,6 +120,11 @@ export class AppLayoutComponent implements OnInit { this.displayBetaBanner = true; } + + public viewUserProjects() { + this.router.navigate(['user/projects']); + } + /** * Method which triggers when the user clicks on the burger menu in the header. * Toggles the navbar visibility From 566096044c0923324570c87ce7957bb2b60e20cb Mon Sep 17 00:00:00 2001 From: macfleury-2000 Date: Thu, 17 Jun 2021 11:17:44 +0200 Subject: [PATCH 15/30] removed pagination an fixed loaded projects --- .../user-project/user-project.component.html | 49 ++----------------- .../user-project/user-project.component.ts | 19 +------ 2 files changed, 5 insertions(+), 63 deletions(-) diff --git a/src/app/modules/user/user-project/user-project.component.html b/src/app/modules/user/user-project/user-project.component.html index 30f124bf..ecf89e58 100644 --- a/src/app/modules/user/user-project/user-project.component.html +++ b/src/app/modules/user/user-project/user-project.component.html @@ -70,29 +70,13 @@

{{ name }}

- - -

Pagination

-
- - +
@@ -105,33 +89,6 @@

There are no projects available.

-
- - - - - - - - - - - - - - - - - - -
+
diff --git a/src/app/modules/user/user-project/user-project.component.ts b/src/app/modules/user/user-project/user-project.component.ts index 9512fef1..9942c618 100644 --- a/src/app/modules/user/user-project/user-project.component.ts +++ b/src/app/modules/user/user-project/user-project.component.ts @@ -25,8 +25,6 @@ import { ProjectCategory } from 'src/app/models/domain/projectCategory'; import { SearchResultsResource } from 'src/app/models/resources/search-results'; import { AuthService } from 'src/app/services/auth.service'; import { FileRetrieverService } from 'src/app/services/file-retriever.service'; -import { InternalSearchService } from 'src/app/services/internal-search.service'; -import { PaginationService } from 'src/app/services/pagination.service'; import { UserService } from 'src/app/services/user.service'; import { ProjectDetailModalUtility } from 'src/app/utils/project-detail-modal.util'; import { InternalSearchQuery } from 'src/app/models/resources/internal-search-query'; @@ -171,8 +169,6 @@ export class UserProjectComponent implements OnInit { private fileRetrieverService: FileRetrieverService, private modalUtility: ProjectDetailModalUtility, private authService: AuthService, - private internalSearchService: InternalSearchService, - private paginationService: PaginationService, private seoService: SEOService, private location: Location, private modalService: BsModalService, @@ -199,6 +195,7 @@ export class UserProjectComponent implements OnInit { .pipe(finalize(() => (this.userprojectsLoading = false))) .subscribe((result) => { this.userprojects = result; + console.log(this.userprojects) this.userprojects.forEach(element => { element.likeCount = element.likes.length; }); @@ -365,19 +362,7 @@ export class UserProjectComponent implements OnInit { this.updateQueryParams(); - if (internalSearchQuery.query == null) { - // No search query provided use projectService. - this.paginationService - .getProjectsPaginated(internalSearchQuery) - .pipe(finalize(() => (this.userprojectsLoading = false))) - .subscribe((result) => this.handleSearchAndProjectResponse(result)); - } else { - // Search query provided use searchService. - this.internalSearchService - .getSearchResultsPaginated(internalSearchQuery) - .pipe(finalize(() => (this.userprojectsLoading = false))) - .subscribe((result) => this.handleSearchAndProjectResponse(result)); - } + } /** From 80a21a108579bcebb753e8e0a6ce8486e9c335bf Mon Sep 17 00:00:00 2001 From: macfleury-2000 Date: Thu, 17 Jun 2021 11:48:44 +0200 Subject: [PATCH 16/30] Styling fixes and updated changelog --- CHANGELOG.md | 1 + src/app/components/app-layout/app-layout.component.html | 3 ++- .../modules/user/user-project/user-project.component.html | 8 ++++++-- .../modules/user/user-project/user-project.component.scss | 5 +++++ 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9281b10b..baf22f1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ### Added +- Added my projects page - [#505](https://github.com/DigitalExcellence/dex-frontend/issues/505) ### Changed diff --git a/src/app/components/app-layout/app-layout.component.html b/src/app/components/app-layout/app-layout.component.html index 2aaad2c2..9f12b315 100644 --- a/src/app/components/app-layout/app-layout.component.html +++ b/src/app/components/app-layout/app-layout.component.html @@ -52,8 +52,9 @@ diff --git a/src/app/modules/user/user-project/user-project.component.html b/src/app/modules/user/user-project/user-project.component.html index ecf89e58..cdaae876 100644 --- a/src/app/modules/user/user-project/user-project.component.html +++ b/src/app/modules/user/user-project/user-project.component.html @@ -63,10 +63,14 @@

My projects

- +

{{ name }}

-

Projects: {{ userprojects.length }}

+
+

Projects:

+

{{ userprojects.length }}

+ +
diff --git a/src/app/modules/user/user-project/user-project.component.scss b/src/app/modules/user/user-project/user-project.component.scss index d66d3274..9d3381cd 100644 --- a/src/app/modules/user/user-project/user-project.component.scss +++ b/src/app/modules/user/user-project/user-project.component.scss @@ -39,6 +39,11 @@ height: calc(100% - 30px); margin: 30px; } + + .user-amounts{ + display: grid; + grid-template-columns: auto auto; + } } .project-chooser{ From 765e32d354f570dcdb018f41ae45cec92719ada3 Mon Sep 17 00:00:00 2001 From: macfleury-2000 Date: Thu, 17 Jun 2021 14:10:50 +0200 Subject: [PATCH 17/30] fixed routing --- src/app/modules/user/user-project/user-project.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/modules/user/user-project/user-project.component.ts b/src/app/modules/user/user-project/user-project.component.ts index 9942c618..4c17f8f1 100644 --- a/src/app/modules/user/user-project/user-project.component.ts +++ b/src/app/modules/user/user-project/user-project.component.ts @@ -419,7 +419,7 @@ export class UserProjectComponent implements OnInit { category => category.selected ? category.id : null) .filter(category => category) )}`; - this.location.replaceState(`/project/overview/`, queryString); + this.location.replaceState(`/user/projects`, queryString); this.updateSEOTags(); this.onInternalQueryChange(); } From 90c104f099d6bb6d565f2bcb41e40ea8baf6a856 Mon Sep 17 00:00:00 2001 From: Walter Sajtos Date: Tue, 22 Jun 2021 13:51:40 +0200 Subject: [PATCH 18/30] Code cleanup --- .../app-layout/app-layout.component.ts | 4 +- .../project/overview/overview.component.ts | 3 +- .../user-project/user-project.component.ts | 512 ------------------ .../user-projects.component.html} | 27 +- .../user-projects.component.scss} | 0 .../user-projects/user-projects.component.ts | 200 +++++++ src/app/modules/user/user-routing.module.ts | 4 +- src/app/modules/user/user.module.ts | 19 +- src/app/services/user.service.ts | 23 +- 9 files changed, 235 insertions(+), 557 deletions(-) delete mode 100644 src/app/modules/user/user-project/user-project.component.ts rename src/app/modules/user/{user-project/user-project.component.html => user-projects/user-projects.component.html} (77%) rename src/app/modules/user/{user-project/user-project.component.scss => user-projects/user-projects.component.scss} (100%) create mode 100644 src/app/modules/user/user-projects/user-projects.component.ts diff --git a/src/app/components/app-layout/app-layout.component.ts b/src/app/components/app-layout/app-layout.component.ts index fd7d2b41..45afa7ac 100644 --- a/src/app/components/app-layout/app-layout.component.ts +++ b/src/app/components/app-layout/app-layout.component.ts @@ -23,7 +23,7 @@ import { AlertService } from 'src/app/services/alert.service'; import { NavigationEnd, NavigationStart, Router } from '@angular/router'; /** - * Component used to display the basic layout of the application. + * Component used to display the basic layout of the application. */ @Component({ selector: 'app-layout', @@ -120,7 +120,7 @@ export class AppLayoutComponent implements OnInit { this.displayBetaBanner = true; } - + public viewUserProjects() { this.router.navigate(['user/projects']); } diff --git a/src/app/modules/project/overview/overview.component.ts b/src/app/modules/project/overview/overview.component.ts index 0b5fd7b6..f1128140 100644 --- a/src/app/modules/project/overview/overview.component.ts +++ b/src/app/modules/project/overview/overview.component.ts @@ -52,7 +52,6 @@ export class OverviewComponent implements OnInit, AfterViewInit { public projectsToDisplay: Project[] = []; public projectsTotal: Project[] = []; - /** * Determine whether we need to render a list or cart view */ @@ -146,7 +145,7 @@ export class OverviewComponent implements OnInit, AfterViewInit { private paginationService: PaginationService, private internalSearchService: InternalSearchService, private formBuilder: FormBuilder, - private activatedRoute: ActivatedRoute, + private activatedRoute: ActivatedRoute, private seoService: SEOService, private modalService: BsModalService, private location: Location, diff --git a/src/app/modules/user/user-project/user-project.component.ts b/src/app/modules/user/user-project/user-project.component.ts deleted file mode 100644 index 4c17f8f1..00000000 --- a/src/app/modules/user/user-project/user-project.component.ts +++ /dev/null @@ -1,512 +0,0 @@ -/* - * Digital Excellence Copyright (C) 2020 Brend Smits - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You can find a copy of the GNU Lesser General Public License - * along with this program, in the LICENSE.md file in the root project directory. - * If not, see https://www.gnu.org/licenses/lgpl-3.0.txt - */ - -import { AfterViewInit, Component, OnInit } from '@angular/core'; -import { SafeUrl } from '@angular/platform-browser'; -import { ActivatedRoute, Router } from '@angular/router'; -import { debounceTime, finalize } from 'rxjs/operators'; -import { SelectFormOption } from 'src/app/interfaces/select-form-option'; -import { Project } from 'src/app/models/domain/project'; -import { ProjectCategory } from 'src/app/models/domain/projectCategory'; -import { SearchResultsResource } from 'src/app/models/resources/search-results'; -import { AuthService } from 'src/app/services/auth.service'; -import { FileRetrieverService } from 'src/app/services/file-retriever.service'; -import { UserService } from 'src/app/services/user.service'; -import { ProjectDetailModalUtility } from 'src/app/utils/project-detail-modal.util'; -import { InternalSearchQuery } from 'src/app/models/resources/internal-search-query'; -import { PageChangedEvent } from 'ngx-bootstrap/pagination'; -import { SEOService } from 'src/app/services/seo.service'; -import { Location } from '@angular/common'; -import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; -import { DetailsComponent } from '../../project/details/details.component'; -import { Subscription } from 'rxjs'; -import { FormBuilder, FormControl } from '@angular/forms'; -import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject'; -import { environment } from 'src/environments/environment'; -import { CategoryService } from 'src/app/services/category.service'; - -@Component({ - selector: 'user-project', - templateUrl: './user-project.component.html', - styleUrls: ['./user-project.component.scss'], -}) -export class UserProjectComponent implements OnInit { - - public sortSelectOptions: SelectFormOption[] = [ - {value: 'updated,desc', viewValue: 'Updated (new-old)'}, - {value: 'updated,asc', viewValue: 'Updated (old-new)'}, - {value: 'name,asc', viewValue: 'Name (a-z)'}, - {value: 'name,desc', viewValue: 'Name (z-a)'}, - {value: 'created,desc', viewValue: 'Created (new-old)'}, - {value: 'created,asc', viewValue: 'Created (old-new)'}, - ]; - - public isAuthenticated: boolean; - public projectsToDisplay: Project[] = []; -; - - - - /** - * FormControl for getting the input. - */ - public sortOptionControl: FormControl = null; - public paginationOptionControl: FormControl = null; - public searchControl: FormControl = null - - public categories: ProjectCategory[]; - - - public name: string; - public photo : File; - public subscription: Subscription; - /** - * The number of projects that are on the platform - */ - public totalNrOfProjects = 0; - - /** - * Boolean to determine whether the component is loading the information from the api. - */ - public projectsLoading = true; - - /** - * Stores the response with the paginated projects etc. from the api. - */ - public paginationResponse: SearchResultsResource; - - public showListView: boolean = false; - - public showPaginationFooter = true; - public currentPage; - - /** - * The possible pagination options for the dropdown - */ - public paginationDropDownOptions = [ - {id: 0, amountOnPage: 12}, - {id: 1, amountOnPage: 24}, - {id: 2, amountOnPage: 36}, - ]; - - /** - * Default pagination option for the dropdown - */ - public defaultPaginationOption = { - id: 0, - amountOnPage: 12 - }; - - - /** - * Parameters for keeping track of the current internalSearch query values. - */ - private currentSortOptions: string = this.sortSelectOptions[0].value; - - /** - * The amount of projects that will be displayed on a single page. - */ - public amountOfProjectsOnSinglePage = 12; - /** - * Array to receive and store the projects from the api. - */ - public userprojects: Project[] = []; - - /** - * Boolean to determine whether the component is loading the information from the api. - */ - public userprojectsLoading = true; - - private searchSubject = new BehaviorSubject(null); - - /** - * Array to receive and store the projects from the api. - */ - // public projects: Project[] = []; - // public projectsTotal: Project[] = []; - - public displaySearchElements = false; - - - /** - * Project parameter gets updated per project detail modal - */ - public currentProject: Project = null; - - /** - * Parameters for keeping track of the current internalSearch query values. - */ - private currentSearchInput: string; - private currentSortType: string = this.currentSortOptions.split(',')[0]; - private currentSortDirection: string = this.currentSortOptions.split(',')[1]; - - /** - * Property to indicate whether the project is loading. - */ - private projectLoading = true; - - - private modalRef: BsModalRef; - private modalSubscriptions: Subscription[] = []; - - - constructor(private userService: UserService, - private router: Router, - private fileRetrieverService: FileRetrieverService, - private modalUtility: ProjectDetailModalUtility, - private authService: AuthService, - private seoService: SEOService, - private location: Location, - private modalService: BsModalService, - private formBuilder: FormBuilder, - private activatedRoute: ActivatedRoute, - private categoryService: CategoryService, - private route: ActivatedRoute) { - this.searchControl = new FormControl(''); - this.sortOptionControl = new FormControl(this.sortSelectOptions); - this.paginationOptionControl = new FormControl(this.paginationDropDownOptions[0]); - - } - - ngOnInit(): void { - this.subscription = this.authService.authNavStatus$.subscribe((status) => { - this.isAuthenticated = status; - this.name = this.authService.name; - }); - - this.authService.authNavStatus$.subscribe((status) => { - this.isAuthenticated = status; - if (status) { - this.userService.getProjectsFromUser() - .pipe(finalize(() => (this.userprojectsLoading = false))) - .subscribe((result) => { - this.userprojects = result; - console.log(this.userprojects) - this.userprojects.forEach(element => { - element.likeCount = element.likes.length; - }); - // this.projectsToDisplay = this.userprojects; - }); - } - }); - - // Subscribe to search subject to debounce the input and afterwards searchAndFilter. - this.searchSubject - .pipe( - debounceTime(500) - ) - .subscribe((result) => { - if (!result) { - return; - } - this.onInternalQueryChange(); - }); - - this.searchControl.valueChanges.subscribe((value) => this.onSearchInputValueChange(value)); - - this.updateSEOTags(); - } - - ngAfterViewInit() { - this.categoryService.getAll().subscribe(categories => { - this.categories = categories; - this.processQueryParams(); - }); - - this.activatedRoute.params.subscribe(params => { - const projectId = params.id?.split('-')[0]; - this.createProjectModal(projectId); - }); - } - public onClickUserProject(id: number, name: string): void { - name = name.split(' ').join('-'); - this.modalUtility.openProjectModal(id, name, '/home'); - } - - public onCategoryClick(category): void { - this.categories = this.categories.map(cat => ( - cat.name === category.name - ? {...cat, selected: !category.selected} - : {...cat} - )); - } - - /** - * Method which triggers when the serach input receives a key up. - * Updates the search subject with the query. - * @param $event the event containing the info of the keyboard press. - */ - public onSearchInputValueChange(value: string): void { - // Do nothing if input did not change. - if (this.currentSearchInput === value) { - return; - } - - // Do nothing if the input contains only spaces or line breaks AND the value is not already empty. - // Indicating that the search was cleared and a new request should be made. - if (value !== '' && !value.replace(/\s/g, '').length) { - return; - } - - this.currentSearchInput = value; - this.searchSubject.next(value); - } - - /** - * Checks whether there are any projects - */ - public projectsEmpty(): boolean { - return this.userprojects.length < 1; - } - - /** - * Triggers on project click in the list. - * @param event click event - * @param id project id. - * @param name project name - */ - public onClickProject(event: Event, id: number, name: string): void { - name = name.split(' ').join('-'); - - const clickedSection = event.target as Element; - - if (clickedSection.classList.contains('project-collaborators')) { - this.createProjectModal(id, 'collaborators'); - } else { - this.createProjectModal(id); - } - this.location.replaceState(`/project/details/${id}-${name}`); - } - /** - * Method to get the url of the icon of the project. This is retrieved - * from the file retriever service - */ - public getIconUrl(project: Project): SafeUrl { - return this.fileRetrieverService.getIconUrl(project.projectIcon); - } - - /** - * Method that retrieves the page of the pagination footer when the user selects a new one. - * @param event holds the current page of the pagination footer, as well as the amount - * of projects that are being displayed on a single page. - */ - public pageChanged(event: PageChangedEvent): void { - this.currentPage = event.page; - this.onInternalQueryChange(); - } - - /** - * Method that retrieves the value that has changed from the pagination dropdown in the accordion, - * and based on that value retrieves the paginated projects with the right parameters. - * @param $event the identifier of the selected value. - */ - public onPaginationChange() { - this.amountOfProjectsOnSinglePage = this.paginationOptionControl.value.amountOnPage; - if (this.amountOfProjectsOnSinglePage === this.paginationResponse.totalCount) { - this.currentPage = 1; - } - this.onInternalQueryChange(); - } - - /** - * Method to handle value changes of the sort form. - * @param value the value of the form. - */ - public onSortFormValueChange(): void { - if (!this.sortOptionControl.value) { - return; - } - this.currentSortType = this.sortOptionControl.value.value.split(',')[0]; - this.currentSortDirection = this.sortOptionControl.value.value.split(',')[1]; - this.onInternalQueryChange(); - } - - public onCategoryChange(categoryId: number): void { - this.categories = this.categories.map(category => - category.id === categoryId - ? {...category, selected: !category.selected} - : category); - this.onInternalQueryChange(); - } - - /** - * Method to build the new internal search query when any of it params have changed. - * Calls the projectService or searchService based on the value of the query. - */ - private onInternalQueryChange(): void { - const internalSearchQuery: InternalSearchQuery = { - query: this.currentSearchInput === '' ? null : this.currentSearchInput, - // If there is a search query, search on all pages - page: !this.currentSearchInput ? this.currentPage : null, - amountOnPage: this.amountOfProjectsOnSinglePage, - sortBy: this.currentSortType, - sortDirection: this.currentSortDirection, - categories: this.categories - .map(value => value.selected ? value.id : null) - .filter(value => value) - }; - - this.updateQueryParams(); - - - } - - /** - * Method to handle the response of the call to the project or search service. - */ - private handleSearchAndProjectResponse(response: SearchResultsResource): void { - this.paginationResponse = response; - - this.userprojects = response.results; - this.projectsToDisplay = response.results; - this.totalNrOfProjects = response.totalCount; - - if (this.userprojects.length < this.amountOfProjectsOnSinglePage && this.currentPage <= 1) { - this.showPaginationFooter = false; - } else { - this.showPaginationFooter = true; - } - } - - /** - * Method to open the modal for a projects detail - * @param projectId the id of the project that should be shown. - * @param activeTab Define the active tab - */ - private createProjectModal(projectId: number, activeTab: string = 'description') { - const initialState = { - projectId: projectId, - activeTab: activeTab - }; - if (projectId) { - this.modalRef = this.modalService.show(DetailsComponent, {animated: true, initialState}); - this.modalRef.setClass('project-modal'); - - this.modalRef.content.onLike.subscribe(isLiked => { - const projectIndexToUpdate = this.userprojects.findIndex(project => project.id === projectId); - if (isLiked) { - this.userprojects[projectIndexToUpdate].likeCount++; - this.userprojects[projectIndexToUpdate].userHasLikedProject = true; - } else { - this.userprojects[projectIndexToUpdate].likeCount--; - this.userprojects[projectIndexToUpdate].userHasLikedProject = false; - } - }); - - // Go back to home page after the modal is closed - this.modalSubscriptions.push( - this.modalService.onHide.subscribe(() => { - if (this.location.path().startsWith('/project/details')) { - const queryString = `query=${this.searchControl.value}` - + `&sortOption=${this.currentSortOptions}` - + `&pagination=${this.amountOfProjectsOnSinglePage}` - + `&page=${this.currentPage}` - + `&categories=${JSON.stringify(this.categories?.map( - category => category.selected ? category.id : null) - .filter(category => category) - )}`; - this.location.replaceState(`/user/projects`, queryString); - this.updateSEOTags(); - this.onInternalQueryChange(); - } - } - )); - } - } - - private updateQueryParams() { - this.router.navigate( - [], - { - queryParams: { - query: this.searchControl.value, - sortOption: this.currentSortOptions, - pagination: this.amountOfProjectsOnSinglePage, - categories: JSON.stringify( - this.categories?.map(category => - category.selected ? category.id : null - ).filter(category => category) - ) - }, - queryParamsHandling: 'merge' - }); - } - - private processQueryParams() { - this.route.queryParams.subscribe(({query, categories: selectedCategories, sortOption, pagination}) => { - if (query !== 'null' && query !== 'undefined') { - this.searchControl.setValue(query); - } - - if (selectedCategories) { - selectedCategories = JSON.parse(selectedCategories); - if (selectedCategories.count > 0) { - this.categories = this.categories?.map(category => { - return { - ...category, - selected: selectedCategories.contains(category.id) - }; - }); - } - } - - if (sortOption) { - this.currentSortOptions = sortOption; - this.sortOptionControl.setValue(this.sortSelectOptions.find(option => option.value === sortOption)); - } - - if (pagination) { - const parsed = this.paginationDropDownOptions.find(option => - option.amountOnPage === parseInt(pagination, 10)); - - this.paginationOptionControl.setValue(parsed ? parsed : 12); - this.amountOfProjectsOnSinglePage = parsed ? parsed.amountOnPage : 12; - } - - this.onInternalQueryChange(); - }); - } - - /** - * Methods to update the title and description through the SEO service - */ - private updateSEOTags() { - // Updates meta and title tags - this.seoService.updateTitle('Project overview'); - this.seoService.updateDescription('Browse or search for specific projects or ideas within DeX'); - } - - /** - * Method to make tags change appearance on clicking. - * further implementation is still pending. - */ - public tagClicked(event) { - if (event.target.className === 'tag clicked') { - event.target.className = 'tag'; - } else { - event.target.className = 'tag clicked'; - } - } - - /** - * Method to display the tags based on the environment variable. - * Tags should be hidden in production for now until further implementation is finished. - */ - public displayTags(): boolean { - return !environment.production; - } - } \ No newline at end of file diff --git a/src/app/modules/user/user-project/user-project.component.html b/src/app/modules/user/user-projects/user-projects.component.html similarity index 77% rename from src/app/modules/user/user-project/user-project.component.html rename to src/app/modules/user/user-projects/user-projects.component.html index cdaae876..3a200e7a 100644 --- a/src/app/modules/user/user-project/user-project.component.html +++ b/src/app/modules/user/user-projects/user-projects.component.html @@ -16,26 +16,7 @@ If not, see https://www.gnu.org/licenses/lgpl-3.0.txt --> - - -
+
@@ -65,7 +46,7 @@

My projects

-

{{ name }}

+

{{ userName }}

Projects:

{{ userprojects.length }}

@@ -74,8 +55,6 @@

{{ name }}

- -
{{ name }}

There are no projects available.

- -
diff --git a/src/app/modules/user/user-project/user-project.component.scss b/src/app/modules/user/user-projects/user-projects.component.scss similarity index 100% rename from src/app/modules/user/user-project/user-project.component.scss rename to src/app/modules/user/user-projects/user-projects.component.scss diff --git a/src/app/modules/user/user-projects/user-projects.component.ts b/src/app/modules/user/user-projects/user-projects.component.ts new file mode 100644 index 00000000..c6b2a1ca --- /dev/null +++ b/src/app/modules/user/user-projects/user-projects.component.ts @@ -0,0 +1,200 @@ +/* + * Digital Excellence Copyright (C) 2020 Brend Smits + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You can find a copy of the GNU Lesser General Public License + * along with this program, in the LICENSE.md file in the root project directory. + * If not, see https://www.gnu.org/licenses/lgpl-3.0.txt + */ + +import { Component, OnInit } from '@angular/core'; +import { SafeUrl } from '@angular/platform-browser'; +import { ActivatedRoute, Router } from '@angular/router'; +import { finalize } from 'rxjs/operators'; +import { Project } from 'src/app/models/domain/project'; +import { AuthService } from 'src/app/services/auth.service'; +import { FileRetrieverService } from 'src/app/services/file-retriever.service'; +import { UserService } from 'src/app/services/user.service'; +import { ProjectDetailModalUtility } from 'src/app/utils/project-detail-modal.util'; +import { SEOService } from 'src/app/services/seo.service'; +import { Location } from '@angular/common'; +import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; +import { DetailsComponent } from 'src/app/modules/project/details/details.component'; +import { environment } from 'src/environments/environment'; + +@Component({ + selector: 'user-project', + templateUrl: './user-projects.component.html', + styleUrls: ['./user-projects.component.scss'], +}) +export class UserProjectsComponent implements OnInit { + public projectsToDisplay: Project[] = []; + + /** + * User info + */ + public userName: string; + + /** + * The number of projects that belong to the user + */ + public totalNrOfProjects = 0; + + /** + * Boolean to determine whether the component is loading the information from the api. + */ + public projectsLoading = true; + + public showListView = false; + + public showPaginationFooter = true; + public currentPage; + + /** + * Array to receive and store the projects from the api. + */ + public userprojects: Project[] = []; + + /** + * Boolean to determine whether the component is loading the information from the api. + */ + public userProjectsLoading = true; + + /** + * Project parameter gets updated per project detail modal + */ + public currentProject: Project = null; + + private modalRef: BsModalRef; + + constructor(private userService: UserService, + private router: Router, + private fileRetrieverService: FileRetrieverService, + private modalUtility: ProjectDetailModalUtility, + private authService: AuthService, + private seoService: SEOService, + private location: Location, + private modalService: BsModalService, + private activatedRoute: ActivatedRoute) {} + + ngOnInit(): void { + this.authService.authNavStatus$.subscribe(status => { + this.userName = this.authService.name; + if (status) { + this.userService.getProjectsFromUser() + .pipe( + finalize(() => ( + this.userProjectsLoading = false + )) + ).subscribe(result => { + this.userprojects = result; + }); + } + }); + this.updateSEOTags(); + } + + ngAfterViewInit() { + this.activatedRoute.params.subscribe(params => { + const projectId = params.id?.split('-')[0]; + this.createProjectModal(projectId); + }); + } + + public onClickUserProject(id: number, name: string): void { + name = name.split(' ').join('-'); + this.modalUtility.openProjectModal(id, name, '/home'); + } + + /** + * Checks whether there are any projects + */ + public projectsEmpty(): boolean { + return this.userprojects.length < 1; + } + + /** + * Triggers on project click in the list. + * @param event click event + * @param id project id. + * @param name project name + */ + public onClickProject(event: Event, id: number, name: string): void { + name = name.split(' ').join('-'); + + const clickedSection = event.target as Element; + + if (clickedSection.classList.contains('project-collaborators')) { + this.createProjectModal(id, 'collaborators'); + } else { + this.createProjectModal(id); + } + this.location.replaceState(`/project/details/${id}-${name}`); + } + + /** + * Method to get the url of the icon of the project. This is retrieved + * from the file retriever service + */ + public getIconUrl(project: Project): SafeUrl { + return this.fileRetrieverService.getIconUrl(project.projectIcon); + } + + /** + * Method to open the modal for a projects detail + * @param projectId the id of the project that should be shown. + * @param activeTab Define the active tab + */ + private createProjectModal(projectId: number, activeTab: string = 'description') { + const initialState = { + projectId: projectId, + activeTab: activeTab + }; + if (projectId) { + this.modalRef = this.modalService.show(DetailsComponent, {animated: true, initialState}); + this.modalRef.setClass('project-modal'); + + this.modalRef.content.onLike.subscribe(isLiked => { + const projectIndexToUpdate = this.userprojects.findIndex(project => project.id === projectId); + if (isLiked) { + this.userprojects[projectIndexToUpdate].likeCount++; + this.userprojects[projectIndexToUpdate].userHasLikedProject = true; + } else { + this.userprojects[projectIndexToUpdate].likeCount--; + this.userprojects[projectIndexToUpdate].userHasLikedProject = false; + } + }); + + // Go back to home page after the modal is closed + this.modalService.onHide.subscribe(() => { + this.location.replaceState(`/user/projects`); + this.updateSEOTags(); + }); + } + } + + /** + * Methods to update the title and description through the SEO service + */ + private updateSEOTags() { + // Updates meta and title tags + this.seoService.updateTitle('User projects'); + this.seoService.updateDescription('View your own projects within DeX'); + } + + /** + * Method to display the tags based on the environment variable. + * Tags should be hidden in production for now until further implementation is finished. + */ + public displayTags(): boolean { + return !environment.production; + } +} diff --git a/src/app/modules/user/user-routing.module.ts b/src/app/modules/user/user-routing.module.ts index f120eb50..d3bb0672 100644 --- a/src/app/modules/user/user-routing.module.ts +++ b/src/app/modules/user/user-routing.module.ts @@ -1,10 +1,10 @@ import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; -import { UserProjectComponent } from './user-project/user-project.component'; +import { UserProjectsComponent } from './user-projects/user-projects.component'; const routes: Routes = [ - { path: 'projects', component: UserProjectComponent }, + { path: 'projects', component: UserProjectsComponent }, ]; @NgModule({ diff --git a/src/app/modules/user/user.module.ts b/src/app/modules/user/user.module.ts index dddc9809..367edea1 100644 --- a/src/app/modules/user/user.module.ts +++ b/src/app/modules/user/user.module.ts @@ -1,26 +1,21 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; - import { UserRoutingModule } from './user-routing.module'; -import { UserProjectComponent } from './user-project/user-project.component'; -import { PaginationModule } from 'ngx-bootstrap/pagination'; -import { ProjectModule } from '../project/project.module'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { UserProjectsComponent } from './user-projects/user-projects.component'; +import { ProjectModule } from 'src/app/modules/project/project.module'; +import { FormsModule } from '@angular/forms'; @NgModule({ declarations: [ - UserProjectComponent + UserProjectsComponent ], imports: [ CommonModule, UserRoutingModule, - PaginationModule.forRoot(), ProjectModule, - FormsModule, - CommonModule, - FormsModule, - ReactiveFormsModule, + FormsModule ] }) -export class UserModule { } +export class UserModule { +} diff --git a/src/app/services/user.service.ts b/src/app/services/user.service.ts index ca7fc992..4992a3a7 100644 --- a/src/app/services/user.service.ts +++ b/src/app/services/user.service.ts @@ -21,8 +21,9 @@ import { API_CONFIG } from 'src/app/config/api-config'; import { User } from 'src/app/models/domain/user'; import { UserAdd } from 'src/app/models/resources/user-add'; import { HttpBaseService } from './http-base.service'; -import { Observable } from 'rxjs'; +import { from, Observable } from 'rxjs'; import { Project } from 'src/app/models/domain/project'; +import { mergeMap } from 'rxjs/operators'; @Injectable({ providedIn: 'root', @@ -38,6 +39,24 @@ export class UserService extends HttpBaseService { } public getProjectsFromUser(): Observable { - return this.http.get(`${this.url}/projects`); + return this.http.get(`${this.url}/projects`) + .pipe( + mergeMap(result => from( + this.addLikes(result) + )) + ); + } + + private addLikes(projects): Promise { + return new Promise(resolve => { + this.getCurrentUser().subscribe(currentUser => { + projects.map(project => { + project.likeCount = project.likes.length ? project.likes.length : 0; + project.userHasLikedProject = project.likes.filter(like => like.userId === currentUser?.id).length > 0; + return project; + }); + resolve(projects); + }); + }); } } From a85639d895f93954c79fe40a9d8393a926ae5739 Mon Sep 17 00:00:00 2001 From: macfleury-2000 Date: Fri, 25 Jun 2021 13:12:23 +0200 Subject: [PATCH 19/30] responsive fix --- .../modules/user/user-projects/user-projects.component.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/app/modules/user/user-projects/user-projects.component.scss b/src/app/modules/user/user-projects/user-projects.component.scss index 9d3381cd..d1be7178 100644 --- a/src/app/modules/user/user-projects/user-projects.component.scss +++ b/src/app/modules/user/user-projects/user-projects.component.scss @@ -28,6 +28,10 @@ position: relative; margin-bottom: 50px; + @media only screen and (max-width: 720px) { + width: 100%; + } + .profile-picture{ width: 120px; height: 120px; From 4580d83499916f4167df9e4522e8159de60e37ad Mon Sep 17 00:00:00 2001 From: macfleury-2000 Date: Fri, 25 Jun 2021 13:23:53 +0200 Subject: [PATCH 20/30] Added comments and removed useless CSS files --- .../auth-callback/auth-callback.component.css | 19 ------------------- .../auth-callback.component.css.map | 9 --------- src/app/modules/home/main/main.component.css | 1 - .../modules/home/main/main.component.css.map | 9 --------- .../user-projects/user-projects.component.ts | 15 ++++++++++++++- 5 files changed, 14 insertions(+), 39 deletions(-) delete mode 100644 src/app/components/auth-callback/auth-callback.component.css delete mode 100644 src/app/components/auth-callback/auth-callback.component.css.map delete mode 100644 src/app/modules/home/main/main.component.css delete mode 100644 src/app/modules/home/main/main.component.css.map diff --git a/src/app/components/auth-callback/auth-callback.component.css b/src/app/components/auth-callback/auth-callback.component.css deleted file mode 100644 index 7b95518c..00000000 --- a/src/app/components/auth-callback/auth-callback.component.css +++ /dev/null @@ -1,19 +0,0 @@ -/* - * - * Digital Excellence Copyright (C) 2020 Brend Smits - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You can find a copy of the GNU Lesser General Public License - * along with this program, in the LICENSE.md file in the root project directory. - * If not, see https://www.gnu.org/licenses/lgpl-3.0.txt - * - */ -/*# sourceMappingURL=auth-callback.component.css.map */ \ No newline at end of file diff --git a/src/app/components/auth-callback/auth-callback.component.css.map b/src/app/components/auth-callback/auth-callback.component.css.map deleted file mode 100644 index d10a1ce6..00000000 --- a/src/app/components/auth-callback/auth-callback.component.css.map +++ /dev/null @@ -1,9 +0,0 @@ -{ - "version": 3, - "mappings": "AAAA;;;;;;;;;;;;;;;;;GAiBG", - "sources": [ - "auth-callback.component.scss" - ], - "names": [], - "file": "auth-callback.component.css" -} \ No newline at end of file diff --git a/src/app/modules/home/main/main.component.css b/src/app/modules/home/main/main.component.css deleted file mode 100644 index 0a132066..00000000 --- a/src/app/modules/home/main/main.component.css +++ /dev/null @@ -1 +0,0 @@ -/* No CSS *//*# sourceMappingURL=main.component.css.map */ \ No newline at end of file diff --git a/src/app/modules/home/main/main.component.css.map b/src/app/modules/home/main/main.component.css.map deleted file mode 100644 index b48e7fdf..00000000 --- a/src/app/modules/home/main/main.component.css.map +++ /dev/null @@ -1,9 +0,0 @@ -{ - "version": 3, - "mappings": "", - "sources": [ - "main.component.scss" - ], - "names": [], - "file": "main.component.css" -} \ No newline at end of file diff --git a/src/app/modules/user/user-projects/user-projects.component.ts b/src/app/modules/user/user-projects/user-projects.component.ts index c6b2a1ca..6b4069b1 100644 --- a/src/app/modules/user/user-projects/user-projects.component.ts +++ b/src/app/modules/user/user-projects/user-projects.component.ts @@ -53,9 +53,19 @@ export class UserProjectsComponent implements OnInit { */ public projectsLoading = true; + /** + * Boolean to determine whether to show the projects in listview or gridview + */ public showListView = false; - public showPaginationFooter = true; + /** + * Boolean to determine whether the pagination footer has to be showed + */ + public showPaginationFooter = true; + + /** + * The pagination page the user is currently on + */ public currentPage; /** @@ -73,6 +83,9 @@ export class UserProjectsComponent implements OnInit { */ public currentProject: Project = null; + /** + * Property to indicate whether the project is loading. + */ private modalRef: BsModalRef; constructor(private userService: UserService, From 21341627928e13f2d53c177b72e63e767d2ad7d0 Mon Sep 17 00:00:00 2001 From: macfleury-2000 Date: Fri, 25 Jun 2021 13:33:39 +0200 Subject: [PATCH 21/30] Revert "Added comments and removed useless CSS files" This reverts commit 4580d83499916f4167df9e4522e8159de60e37ad. --- .../auth-callback/auth-callback.component.css | 19 +++++++++++++++++++ .../auth-callback.component.css.map | 9 +++++++++ src/app/modules/home/main/main.component.css | 1 + .../modules/home/main/main.component.css.map | 9 +++++++++ .../user-projects/user-projects.component.ts | 15 +-------------- 5 files changed, 39 insertions(+), 14 deletions(-) create mode 100644 src/app/components/auth-callback/auth-callback.component.css create mode 100644 src/app/components/auth-callback/auth-callback.component.css.map create mode 100644 src/app/modules/home/main/main.component.css create mode 100644 src/app/modules/home/main/main.component.css.map diff --git a/src/app/components/auth-callback/auth-callback.component.css b/src/app/components/auth-callback/auth-callback.component.css new file mode 100644 index 00000000..7b95518c --- /dev/null +++ b/src/app/components/auth-callback/auth-callback.component.css @@ -0,0 +1,19 @@ +/* + * + * Digital Excellence Copyright (C) 2020 Brend Smits + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You can find a copy of the GNU Lesser General Public License + * along with this program, in the LICENSE.md file in the root project directory. + * If not, see https://www.gnu.org/licenses/lgpl-3.0.txt + * + */ +/*# sourceMappingURL=auth-callback.component.css.map */ \ No newline at end of file diff --git a/src/app/components/auth-callback/auth-callback.component.css.map b/src/app/components/auth-callback/auth-callback.component.css.map new file mode 100644 index 00000000..d10a1ce6 --- /dev/null +++ b/src/app/components/auth-callback/auth-callback.component.css.map @@ -0,0 +1,9 @@ +{ + "version": 3, + "mappings": "AAAA;;;;;;;;;;;;;;;;;GAiBG", + "sources": [ + "auth-callback.component.scss" + ], + "names": [], + "file": "auth-callback.component.css" +} \ No newline at end of file diff --git a/src/app/modules/home/main/main.component.css b/src/app/modules/home/main/main.component.css new file mode 100644 index 00000000..0a132066 --- /dev/null +++ b/src/app/modules/home/main/main.component.css @@ -0,0 +1 @@ +/* No CSS *//*# sourceMappingURL=main.component.css.map */ \ No newline at end of file diff --git a/src/app/modules/home/main/main.component.css.map b/src/app/modules/home/main/main.component.css.map new file mode 100644 index 00000000..b48e7fdf --- /dev/null +++ b/src/app/modules/home/main/main.component.css.map @@ -0,0 +1,9 @@ +{ + "version": 3, + "mappings": "", + "sources": [ + "main.component.scss" + ], + "names": [], + "file": "main.component.css" +} \ No newline at end of file diff --git a/src/app/modules/user/user-projects/user-projects.component.ts b/src/app/modules/user/user-projects/user-projects.component.ts index 6b4069b1..c6b2a1ca 100644 --- a/src/app/modules/user/user-projects/user-projects.component.ts +++ b/src/app/modules/user/user-projects/user-projects.component.ts @@ -53,19 +53,9 @@ export class UserProjectsComponent implements OnInit { */ public projectsLoading = true; - /** - * Boolean to determine whether to show the projects in listview or gridview - */ public showListView = false; - /** - * Boolean to determine whether the pagination footer has to be showed - */ - public showPaginationFooter = true; - - /** - * The pagination page the user is currently on - */ + public showPaginationFooter = true; public currentPage; /** @@ -83,9 +73,6 @@ export class UserProjectsComponent implements OnInit { */ public currentProject: Project = null; - /** - * Property to indicate whether the project is loading. - */ private modalRef: BsModalRef; constructor(private userService: UserService, From 6f212ca4be611c5c248aeec2c6bb7d6b07e21604 Mon Sep 17 00:00:00 2001 From: macfleury-2000 Date: Fri, 25 Jun 2021 13:40:41 +0200 Subject: [PATCH 22/30] Revert "Revert "Added comments and removed useless CSS files"" This reverts commit 21341627928e13f2d53c177b72e63e767d2ad7d0. --- .../auth-callback/auth-callback.component.css | 19 ------------------- .../auth-callback.component.css.map | 9 --------- src/app/modules/home/main/main.component.css | 1 - .../modules/home/main/main.component.css.map | 9 --------- .../user-projects/user-projects.component.ts | 15 ++++++++++++++- 5 files changed, 14 insertions(+), 39 deletions(-) delete mode 100644 src/app/components/auth-callback/auth-callback.component.css delete mode 100644 src/app/components/auth-callback/auth-callback.component.css.map delete mode 100644 src/app/modules/home/main/main.component.css delete mode 100644 src/app/modules/home/main/main.component.css.map diff --git a/src/app/components/auth-callback/auth-callback.component.css b/src/app/components/auth-callback/auth-callback.component.css deleted file mode 100644 index 7b95518c..00000000 --- a/src/app/components/auth-callback/auth-callback.component.css +++ /dev/null @@ -1,19 +0,0 @@ -/* - * - * Digital Excellence Copyright (C) 2020 Brend Smits - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You can find a copy of the GNU Lesser General Public License - * along with this program, in the LICENSE.md file in the root project directory. - * If not, see https://www.gnu.org/licenses/lgpl-3.0.txt - * - */ -/*# sourceMappingURL=auth-callback.component.css.map */ \ No newline at end of file diff --git a/src/app/components/auth-callback/auth-callback.component.css.map b/src/app/components/auth-callback/auth-callback.component.css.map deleted file mode 100644 index d10a1ce6..00000000 --- a/src/app/components/auth-callback/auth-callback.component.css.map +++ /dev/null @@ -1,9 +0,0 @@ -{ - "version": 3, - "mappings": "AAAA;;;;;;;;;;;;;;;;;GAiBG", - "sources": [ - "auth-callback.component.scss" - ], - "names": [], - "file": "auth-callback.component.css" -} \ No newline at end of file diff --git a/src/app/modules/home/main/main.component.css b/src/app/modules/home/main/main.component.css deleted file mode 100644 index 0a132066..00000000 --- a/src/app/modules/home/main/main.component.css +++ /dev/null @@ -1 +0,0 @@ -/* No CSS *//*# sourceMappingURL=main.component.css.map */ \ No newline at end of file diff --git a/src/app/modules/home/main/main.component.css.map b/src/app/modules/home/main/main.component.css.map deleted file mode 100644 index b48e7fdf..00000000 --- a/src/app/modules/home/main/main.component.css.map +++ /dev/null @@ -1,9 +0,0 @@ -{ - "version": 3, - "mappings": "", - "sources": [ - "main.component.scss" - ], - "names": [], - "file": "main.component.css" -} \ No newline at end of file diff --git a/src/app/modules/user/user-projects/user-projects.component.ts b/src/app/modules/user/user-projects/user-projects.component.ts index c6b2a1ca..6b4069b1 100644 --- a/src/app/modules/user/user-projects/user-projects.component.ts +++ b/src/app/modules/user/user-projects/user-projects.component.ts @@ -53,9 +53,19 @@ export class UserProjectsComponent implements OnInit { */ public projectsLoading = true; + /** + * Boolean to determine whether to show the projects in listview or gridview + */ public showListView = false; - public showPaginationFooter = true; + /** + * Boolean to determine whether the pagination footer has to be showed + */ + public showPaginationFooter = true; + + /** + * The pagination page the user is currently on + */ public currentPage; /** @@ -73,6 +83,9 @@ export class UserProjectsComponent implements OnInit { */ public currentProject: Project = null; + /** + * Property to indicate whether the project is loading. + */ private modalRef: BsModalRef; constructor(private userService: UserService, From dcf36dc0450730725db274b67ee09e35242d6216 Mon Sep 17 00:00:00 2001 From: macfleury-2000 Date: Fri, 25 Jun 2021 13:42:40 +0200 Subject: [PATCH 23/30] removed another useless CSS file --- src/app/app.component.css | 19 ------------------- src/app/app.component.css.map | 9 --------- 2 files changed, 28 deletions(-) delete mode 100644 src/app/app.component.css delete mode 100644 src/app/app.component.css.map diff --git a/src/app/app.component.css b/src/app/app.component.css deleted file mode 100644 index 7c75283a..00000000 --- a/src/app/app.component.css +++ /dev/null @@ -1,19 +0,0 @@ -/* - * - * Digital Excellence Copyright (C) 2020 Brend Smits - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You can find a copy of the GNU Lesser General Public License - * along with this program, in the LICENSE.md file in the root project directory. - * If not, see https://www.gnu.org/licenses/lgpl-3.0.txt - * - */ -/*# sourceMappingURL=app.component.css.map */ \ No newline at end of file diff --git a/src/app/app.component.css.map b/src/app/app.component.css.map deleted file mode 100644 index 4bb73eb0..00000000 --- a/src/app/app.component.css.map +++ /dev/null @@ -1,9 +0,0 @@ -{ - "version": 3, - "mappings": "AAAA;;;;;;;;;;;;;;;;;GAiBG", - "sources": [ - "app.component.scss" - ], - "names": [], - "file": "app.component.css" -} \ No newline at end of file From a1664084d7ebba06ce1920a9c02b591b92145438 Mon Sep 17 00:00:00 2001 From: macfleury-2000 Date: Fri, 25 Jun 2021 13:58:01 +0200 Subject: [PATCH 24/30] Fixed trailling whitespace lint error --- src/app/modules/user/user-projects/user-projects.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/modules/user/user-projects/user-projects.component.ts b/src/app/modules/user/user-projects/user-projects.component.ts index 6b4069b1..c2d3e913 100644 --- a/src/app/modules/user/user-projects/user-projects.component.ts +++ b/src/app/modules/user/user-projects/user-projects.component.ts @@ -61,7 +61,7 @@ export class UserProjectsComponent implements OnInit { /** * Boolean to determine whether the pagination footer has to be showed */ - public showPaginationFooter = true; + public showPaginationFooter = true; /** * The pagination page the user is currently on From c52cc0389bc5108e0ef94acfcb37818f996346fa Mon Sep 17 00:00:00 2001 From: Ruben Date: Fri, 25 Jun 2021 15:12:37 +0200 Subject: [PATCH 25/30] Removed commented import line --- src/app/app-routing.module.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index b4d350e0..cbd31974 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -21,7 +21,6 @@ import { AuthCallbackComponent } from './components/auth-callback/auth-callback. import { NotFoundComponent } from './components/not-found/not-found.component'; import { PrivacyPolicyComponent } from './components/privacy-policy/privacy-policy.component'; import { MainComponent } from './modules/home/main/main.component'; -// import { UserModule } from './modules/user/user.module'; const routes: Routes = [ {path: '', redirectTo: '/home', pathMatch: 'full'}, From 00f5ac5b7e6ac8331778f4fd2464bd5dacf093c7 Mon Sep 17 00:00:00 2001 From: Niray Mak <44868678+niraymak@users.noreply.github.com> Date: Mon, 28 Jun 2021 12:33:29 +0200 Subject: [PATCH 26/30] linked loading ngIf to the right boolean --- .../modules/user/user-projects/user-projects.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/modules/user/user-projects/user-projects.component.html b/src/app/modules/user/user-projects/user-projects.component.html index 3a200e7a..da551d92 100644 --- a/src/app/modules/user/user-projects/user-projects.component.html +++ b/src/app/modules/user/user-projects/user-projects.component.html @@ -68,8 +68,8 @@

{{ userName }}

-

-

There are no projects available.

+

+

There are no projects available.

From 04513e9915d8e1f59a2164ef02375e16e928846c Mon Sep 17 00:00:00 2001 From: Walter Sajtos Date: Tue, 29 Jun 2021 11:13:16 +0200 Subject: [PATCH 27/30] Fix infinite loading and dropdown menu --- src/app/components/app-layout/app-layout.component.html | 8 ++++---- .../user/user-projects/user-projects.component.html | 8 ++++++-- .../modules/user/user-projects/user-projects.component.ts | 8 +++++++- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/app/components/app-layout/app-layout.component.html b/src/app/components/app-layout/app-layout.component.html index 9f12b315..335f0e49 100644 --- a/src/app/components/app-layout/app-layout.component.html +++ b/src/app/components/app-layout/app-layout.component.html @@ -33,7 +33,7 @@ diff --git a/src/app/modules/user/user-projects/user-projects.component.html b/src/app/modules/user/user-projects/user-projects.component.html index da551d92..af7be34b 100644 --- a/src/app/modules/user/user-projects/user-projects.component.html +++ b/src/app/modules/user/user-projects/user-projects.component.html @@ -55,7 +55,7 @@

{{ userName }}

- +
{{ userName }}
- + + + + +

There are no projects available.

diff --git a/src/app/modules/user/user-projects/user-projects.component.ts b/src/app/modules/user/user-projects/user-projects.component.ts index c2d3e913..6393eb46 100644 --- a/src/app/modules/user/user-projects/user-projects.component.ts +++ b/src/app/modules/user/user-projects/user-projects.component.ts @@ -83,6 +83,8 @@ export class UserProjectsComponent implements OnInit { */ public currentProject: Project = null; + public noProjects: boolean = false; + /** * Property to indicate whether the project is loading. */ @@ -108,7 +110,11 @@ export class UserProjectsComponent implements OnInit { this.userProjectsLoading = false )) ).subscribe(result => { - this.userprojects = result; + if(result) { + this.userprojects = result; + } else { + this.noProjects = true; + } }); } }); From 6e349e73eed3477a3d08e630fee211517036067a Mon Sep 17 00:00:00 2001 From: Walter Sajtos Date: Tue, 29 Jun 2021 11:19:11 +0200 Subject: [PATCH 28/30] Linter issues --- src/app/modules/user/user-projects/user-projects.component.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/modules/user/user-projects/user-projects.component.html b/src/app/modules/user/user-projects/user-projects.component.html index af7be34b..f2bde1b0 100644 --- a/src/app/modules/user/user-projects/user-projects.component.html +++ b/src/app/modules/user/user-projects/user-projects.component.html @@ -68,6 +68,7 @@

{{ userName }}

+

No projects found

From ba7b9a98f75f55dbc98e670ffd6579308d4c9ec1 Mon Sep 17 00:00:00 2001 From: Walter Sajtos Date: Tue, 29 Jun 2021 11:24:31 +0200 Subject: [PATCH 29/30] Change title size --- .../user/user-projects/user-projects.component.html | 4 ++-- .../modules/user/user-projects/user-projects.component.ts | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/app/modules/user/user-projects/user-projects.component.html b/src/app/modules/user/user-projects/user-projects.component.html index f2bde1b0..b7b31744 100644 --- a/src/app/modules/user/user-projects/user-projects.component.html +++ b/src/app/modules/user/user-projects/user-projects.component.html @@ -68,8 +68,8 @@

{{ userName }}

-

No projects found

- +

No projects found

+
diff --git a/src/app/modules/user/user-projects/user-projects.component.ts b/src/app/modules/user/user-projects/user-projects.component.ts index 6393eb46..6ddd81de 100644 --- a/src/app/modules/user/user-projects/user-projects.component.ts +++ b/src/app/modules/user/user-projects/user-projects.component.ts @@ -83,7 +83,7 @@ export class UserProjectsComponent implements OnInit { */ public currentProject: Project = null; - public noProjects: boolean = false; + public noProjects = false; /** * Property to indicate whether the project is loading. @@ -110,7 +110,7 @@ export class UserProjectsComponent implements OnInit { this.userProjectsLoading = false )) ).subscribe(result => { - if(result) { + if (result) { this.userprojects = result; } else { this.noProjects = true; @@ -216,4 +216,8 @@ export class UserProjectsComponent implements OnInit { public displayTags(): boolean { return !environment.production; } + + public addProjectClicked() { + this.router.navigateByUrl('project/add') + } } From 34174f795d93207f733d59f57758a185a3414528 Mon Sep 17 00:00:00 2001 From: Walter Sajtos Date: Tue, 29 Jun 2021 11:25:28 +0200 Subject: [PATCH 30/30] Linter issue --- src/app/modules/user/user-projects/user-projects.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/modules/user/user-projects/user-projects.component.ts b/src/app/modules/user/user-projects/user-projects.component.ts index 6ddd81de..19e20423 100644 --- a/src/app/modules/user/user-projects/user-projects.component.ts +++ b/src/app/modules/user/user-projects/user-projects.component.ts @@ -218,6 +218,6 @@ export class UserProjectsComponent implements OnInit { } public addProjectClicked() { - this.router.navigateByUrl('project/add') + this.router.navigateByUrl('project/add'); } }