diff --git a/CHANGELOG.md b/CHANGELOG.md index e2611773..e7d89961 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - Added search bar inside navbar with autocomplete suggested results. - [#403](https://github.com/DigitalExcellence/dex-frontend/issues/403) - Refactored the home page. [#380](https://github.com/DigitalExcellence/dex-frontend/issues/380) +- Added project recommendations on the home page. [#497](https://github.com/DigitalExcellence/dex-frontend/issues/497) ### Changed diff --git a/package-lock.json b/package-lock.json index 71ad6e76..ce025374 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3966,7 +3966,7 @@ "colorette": "^1.2.2", "electron-to-chromium": "^1.3.723", "escalade": "^3.1.1", - "node-releases": "^1.1.69" + "node-releases": "^1.1.71" }, "dependencies": { "colorette": { diff --git a/src/app/components/app-layout/app-layout.component.ts b/src/app/components/app-layout/app-layout.component.ts index 5ff82fca..f1c279c4 100644 --- a/src/app/components/app-layout/app-layout.component.ts +++ b/src/app/components/app-layout/app-layout.component.ts @@ -64,7 +64,7 @@ export class AppLayoutComponent implements OnInit { }); this.router.events.subscribe((event) => { - if (event instanceof NavigationStart) { + if (event instanceof NavigationEnd) { if ((event.url === '/home' || event.url === '/')) { this.showSearchbar = true; } else { diff --git a/src/app/modules/home/home.module.ts b/src/app/modules/home/home.module.ts index 14c4d1ea..7ba1feb9 100644 --- a/src/app/modules/home/home.module.ts +++ b/src/app/modules/home/home.module.ts @@ -11,7 +11,8 @@ import { StripHtmlPipe } from 'src/app/utils/striptags.pipe'; import { PopoverModule } from 'ngx-bootstrap/popover'; import { ModalModule } from 'ngx-bootstrap/modal'; import { TooltipModule } from 'ngx-bootstrap/tooltip'; -import { ProjectModule } from 'src/app/modules/project/project.module'; +import { RecommendationCardsComponent } from './recommendations/recommendations.component'; +import { ProjectModule } from '../project/project.module'; @NgModule({ declarations: [ @@ -22,7 +23,9 @@ import { ProjectModule } from 'src/app/modules/project/project.module'; PartnersComponent, ContainerLeftComponent, ContainerRightComponent, - StripHtmlPipe + StripHtmlPipe, + RecommendationCardsComponent + ], imports: [ CommonModule, diff --git a/src/app/modules/home/main/main.component.html b/src/app/modules/home/main/main.component.html index c6135143..8c176d29 100644 --- a/src/app/modules/home/main/main.component.html +++ b/src/app/modules/home/main/main.component.html @@ -1,6 +1,7 @@ - + + diff --git a/src/app/modules/home/recommendations/recommendations.component.html b/src/app/modules/home/recommendations/recommendations.component.html new file mode 100644 index 00000000..886d1d9e --- /dev/null +++ b/src/app/modules/home/recommendations/recommendations.component.html @@ -0,0 +1,38 @@ + + +
+ +
+
+

Your recommended projects

+ +

Your top {{recommendations.length}} recommendations

+
+
+ +
+ + + + + +
+
+
\ No newline at end of file diff --git a/src/app/modules/home/recommendations/recommendations.component.scss b/src/app/modules/home/recommendations/recommendations.component.scss new file mode 100644 index 00000000..90e1e314 --- /dev/null +++ b/src/app/modules/home/recommendations/recommendations.component.scss @@ -0,0 +1,68 @@ +/* + * + * 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"; + + //project recommendations + .recommendedProjects { + // margin-top: 220px; + padding: 40px 60px 20px 60px; + background-color: $light-mode-grey-quaternary; + margin: 0 -39px; + justify-content: center; + align-items: center; + + .inner { + max-width: 1750px; + margin: auto; + width: 100%; + .text { + .large{ + margin: 0 0 5px 0; + } + } + } + + + .cards { + display: grid; + gap: 30px; + max-width: 100%; + grid-auto-columns: 310px; + grid-auto-flow: column; + overflow-x: auto; + overflow-y: hidden; + padding: 20px 0; + + //scrollbar stylingbody + &::-webkit-scrollbar { + height: 4px; + } + + &::-webkit-scrollbar-track { + } + + &::-webkit-scrollbar-thumb { + border-radius: 999px; + background-color: white; + } + + + } +} \ No newline at end of file diff --git a/src/app/modules/home/recommendations/recommendations.component.ts b/src/app/modules/home/recommendations/recommendations.component.ts new file mode 100644 index 00000000..3089317f --- /dev/null +++ b/src/app/modules/home/recommendations/recommendations.component.ts @@ -0,0 +1,86 @@ +/* + * 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 { RecommendationService } from 'src/app/services/recommendation.service'; +import { ProjectDetailModalUtility } from 'src/app/utils/project-detail-modal.util'; + +@Component({ + selector: 'app-recommended-project-cards', + templateUrl: './recommendations.component.html', + styleUrls: ['./recommendations.component.scss'], +}) +export class RecommendationCardsComponent implements OnInit { + + public isAuthenticated: boolean; + + /** + * Array to receive and store the projects from the api. + */ + public recommendations: Project[] = []; + + /** + * Boolean to determine whether the component is loading the information from the api. + */ + public recommendationsLoading = true; + + constructor(private recommendationService: RecommendationService, + private fileRetrieverService: FileRetrieverService, + private modalUtility: ProjectDetailModalUtility, + private authService: AuthService) {} + + ngOnInit(): void { + this.authService.authNavStatus$.subscribe((status) => { + this.isAuthenticated = status; + if (status) { + this.recommendationService.getRecommendations(8) + .pipe(finalize(() => (this.recommendationsLoading = false))) + .subscribe((result) => { + this.recommendations = result; + this.recommendations.forEach(element => { + element.likeCount = element.likes.length; + }); + }); + } + }); + } + + /** +* Triggers on project click in the list. +* @param id project id. +* @param name project name +*/ + public onClickRecommendedProject(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/recommendation.service.ts b/src/app/services/recommendation.service.ts new file mode 100644 index 00000000..e0f86d06 --- /dev/null +++ b/src/app/services/recommendation.service.ts @@ -0,0 +1,39 @@ +/* + * 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 { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { API_CONFIG } from 'src/app/config/api-config'; +import { Observable } from 'rxjs'; +import { Project } from '../models/domain/project'; + +/** + * Service to retrieve autocompleted project suggestions based on typed. + */ +@Injectable({ + providedIn: 'root', +}) +export class RecommendationService { + + protected readonly url = API_CONFIG.url + API_CONFIG.userRoute; + + constructor(private http: HttpClient) {} + + public getRecommendations(amountOfRecommendations): Observable> { + return this.http.get>(this.url + "/projectrecommendations/" + amountOfRecommendations); + } + +}