diff options
Diffstat (limited to 'src/DevHive.Angular')
18 files changed, 327 insertions, 61 deletions
diff --git a/src/DevHive.Angular/src/app/app-constants.module.ts b/src/DevHive.Angular/src/app/app-constants.module.ts index 7552a5e..cbb1ec1 100644 --- a/src/DevHive.Angular/src/app/app-constants.module.ts +++ b/src/DevHive.Angular/src/app/app-constants.module.ts @@ -8,5 +8,9 @@ export class AppConstants { public static API_LANGUAGE_URL = AppConstants.BASE_API_URL + '/Language'; public static API_TECHNOLOGY_URL = AppConstants.BASE_API_URL + '/Technology'; + public static API_POST_URL = AppConstants.BASE_API_URL + '/Post'; + public static API_FEED_URL = AppConstants.BASE_API_URL + '/Feed'; + + public static PAGE_SIZE = 5; public static FALLBACK_PROFILE_ICON = 'assets/images/feed/profile-pic.png'; } diff --git a/src/DevHive.Angular/src/app/components/feed/feed.component.css b/src/DevHive.Angular/src/app/components/feed/feed.component.css index e22693e..f810e83 100644 --- a/src/DevHive.Angular/src/app/components/feed/feed.component.css +++ b/src/DevHive.Angular/src/app/components/feed/feed.component.css @@ -109,6 +109,15 @@ display: none; } +/* Posts */ + +#no-posts-msg { + width: 100%; + margin-top: 1em; + color: gray; + text-align: center; +} + /* Elements, that act as buttons */ #profile-bar > #profile-info:hover, diff --git a/src/DevHive.Angular/src/app/components/feed/feed.component.html b/src/DevHive.Angular/src/app/components/feed/feed.component.html index b82b189..e3c6e83 100644 --- a/src/DevHive.Angular/src/app/components/feed/feed.component.html +++ b/src/DevHive.Angular/src/app/components/feed/feed.component.html @@ -23,8 +23,12 @@ </a> </nav> <div id="posts" class="scroll-standalone"> - <div *ngFor="let post of posts" class="post"> - <app-post></app-post> + <div id="no-posts-msg" *ngIf="posts.length === 0"> + None of your friends have posted anything yet!<br> + Try refreshing your page! + </div> + <div *ngFor="let friendPost of posts" class="post"> + <app-post [paramId]="friendPost.postId.toString()"></app-post> </div> </div> </div> diff --git a/src/DevHive.Angular/src/app/components/feed/feed.component.ts b/src/DevHive.Angular/src/app/components/feed/feed.component.ts index b027e5b..f260fd4 100644 --- a/src/DevHive.Angular/src/app/components/feed/feed.component.ts +++ b/src/DevHive.Angular/src/app/components/feed/feed.component.ts @@ -1,11 +1,12 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; import { Title } from '@angular/platform-browser'; import { Router } from '@angular/router'; import { User } from 'src/models/identity/user'; -import { PostComponent } from '../post/post.component'; import { UserService } from '../../services/user.service'; import { AppConstants } from 'src/app/app-constants.module'; import {HttpErrorResponse} from '@angular/common/http'; +import {FeedService} from 'src/app/services/feed.service'; +import {Post} from 'src/models/post'; @Component({ selector: 'app-feed', @@ -14,26 +15,24 @@ import {HttpErrorResponse} from '@angular/common/http'; }) export class FeedComponent implements OnInit { private _title = 'Feed'; + private _timeLoaded: string; public dataArrived = false; public user: User; - public posts: PostComponent[]; + public posts: Post[] = []; - constructor(private _titleService: Title, private _router: Router, private _userService: UserService) { + constructor(private _titleService: Title, private _router: Router, private _userService: UserService, private _feedService: FeedService) { this._titleService.setTitle(this._title); } ngOnInit(): void { this.user = this._userService.getDefaultUser(); - this.posts = [ - new PostComponent(), - new PostComponent(), - new PostComponent(), - new PostComponent(), - ]; + const now = new Date(); + now.setHours(now.getHours() + 2); // accounting for eastern european timezone + this._timeLoaded = now.toISOString(); if (sessionStorage.getItem('UserCred')) { this._userService.getUserFromSessionStorageRequest().subscribe( - (res: object) => this.finishUserLoading(res), + (res: object) => this.loadFeed(res), (err: HttpErrorResponse) => this.bailOnBadToken() ); } else { @@ -41,8 +40,21 @@ export class FeedComponent implements OnInit { } } - private finishUserLoading(res: object): void { + private loadFeed(res: object): void { Object.assign(this.user, res); + + this._feedService.getUserFeedFromSessionStorageRequest(1, this._timeLoaded, AppConstants.PAGE_SIZE).subscribe( + (result: object) => { + this.posts = Object.values(result)[0]; + this.finishUserLoading(); + }, + (err: HttpErrorResponse) => { + this.finishUserLoading(); + } + ); + } + + private finishUserLoading(): void { if (this.user.imageUrl === '') { this.user.imageUrl = AppConstants.FALLBACK_PROFILE_ICON; } diff --git a/src/DevHive.Angular/src/app/components/post/post.component.css b/src/DevHive.Angular/src/app/components/post/post.component.css index 5395eb2..c3e3caa 100644 --- a/src/DevHive.Angular/src/app/components/post/post.component.css +++ b/src/DevHive.Angular/src/app/components/post/post.component.css @@ -24,6 +24,10 @@ hr { margin-bottom: .2em; } +.author:hover { + cursor: pointer; +} + .author > img { width: 2.2em; height: 2.2em; diff --git a/src/DevHive.Angular/src/app/components/post/post.component.html b/src/DevHive.Angular/src/app/components/post/post.component.html index 487b785..8fbda35 100644 --- a/src/DevHive.Angular/src/app/components/post/post.component.html +++ b/src/DevHive.Angular/src/app/components/post/post.component.html @@ -1,6 +1,6 @@ -<div class="post rounded-border"> +<div class="post rounded-border" *ngIf="loaded"> <div class="content"> - <div class="author"> + <div class="author" (click)="goToAuthorProfile()"> <img class="round-image" [src]="user.imageUrl"> <div class="author-info"> <div class="name"> @@ -12,10 +12,10 @@ </div> </div> <div class="message"> - Your opinion on my idea? + {{ post.message }} </div> <div class="timestamp"> - 17:41 - 27 Dec 2020 + {{ timeCreated }} </div> </div> <div class="rating"> diff --git a/src/DevHive.Angular/src/app/components/post/post.component.ts b/src/DevHive.Angular/src/app/components/post/post.component.ts index 76a4873..7a6b5c0 100644 --- a/src/DevHive.Angular/src/app/components/post/post.component.ts +++ b/src/DevHive.Angular/src/app/components/post/post.component.ts @@ -1,7 +1,12 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; +import {Router} from '@angular/router'; import { Guid } from 'guid-typescript'; import {AppConstants} from 'src/app/app-constants.module'; +import {FeedService} from 'src/app/services/feed.service'; +import {PostService} from 'src/app/services/post.service'; +import {UserService} from 'src/app/services/user.service'; import { User } from 'src/models/identity/user'; +import {Post} from 'src/models/post'; @Component({ selector: 'app-post', @@ -10,23 +15,39 @@ import { User } from 'src/models/identity/user'; }) export class PostComponent implements OnInit { public user: User; + public post: Post; public votesNumber: number; + public timeCreated: string; + public loaded = false; + @Input() paramId: string; - constructor() {} + constructor(private _postService: PostService, private _userService: UserService, private _router: Router) + {} ngOnInit(): void { - // Fetch data in post service - this.user = new User( - Guid.create(), - 'gosho_trapov', - 'Gosho', - 'Trapov', - 'gotra@bg.com', - AppConstants.FALLBACK_PROFILE_ICON, - new Array(), - new Array() - ); + this.post = this._postService.getDefaultPost(); + this.user = this._userService.getDefaultUser(); + this._postService.getPostRequest(Guid.parse(this.paramId)).subscribe( + (result: object) => { + Object.assign(this.post, result); + this.timeCreated = new Date(this.post.timeCreated).toLocaleString('en-GB'); + this.loadUser(); + } + ); this.votesNumber = 23; } + + private loadUser(): void { + this._userService.getUserByUsernameRequest(this.post.creatorUsername).subscribe( + (result: object) => { + Object.assign(this.user, result); + this.loaded = true; + } + ); + } + + goToAuthorProfile(): void { + this._router.navigate(['/profile/' + this.user.userName]); + } } diff --git a/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.css b/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.css index 7e0978d..2aecef5 100644 --- a/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.css +++ b/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.css @@ -50,12 +50,40 @@ hr { transform: translate(0, -1.2em); } +#all-languages, #all-technologies { + display: flex; + flex-wrap: wrap; +} + +#all-languages > *, #all-technologies > * { + width: fit-content; + margin-top: .1em; + margin-bottom: .1em; +} + /* Buttons */ +.edit-btn { + border-radius: 0 !important; + color: var(--focus-color); + background-color: white; + border-color: var(--focus-color); +} + +.edit-btn:hover { + color: white; + background-color: black; + border-color: black !important; +} + .submit-btn { margin-bottom: .5em; } +#update-profile-btn { + margin-top: 1em; +} + #delete-account:hover { color: indianred; border-color: indianred !important; diff --git a/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.html b/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.html index 16b537c..1b713d7 100644 --- a/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.html +++ b/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.html @@ -58,28 +58,42 @@ <label *ngIf="updateUserFormGroup.get('password')?.errors?.pattern" class="error">*At least 1 number</label> </div> </div> - <button type="button" (click)="toggleLanguages()">Edit Languages</button> + <button type="button" class="submit-btn edit-btn" (click)="toggleLanguages()">▼ Edit Languages ▼</button> <div *ngIf="showLanguages"> - Type in your desired languages, separated by a space. - <input type="text" class="input-field" formControlName="languageInput" required> + <div class="input-selection"> + <input type="text" class="input-field" formControlName="languageInput" required> + + <div class="input-errors"> + <label class="error">Type in your desired languages, separated by a space</label> + </div> + </div> Available languages: - <div *ngFor="let lang of availableLanguages"> - {{ lang.name }} + <div id="all-languages"> + <div class="user-language" *ngFor="let lang of availableLanguages"> + {{ lang.name }} + </div> </div> </div> - <button type="button" (click)="toggleTechnologies()">Edit Technologies</button> + <button type="button" class="submit-btn edit-btn" (click)="toggleTechnologies()">▼ Edit Technologies ▼</button> <div *ngIf="showTechnologies"> - Type in your desired technologies, separated by a space. - <input type="text" class="input-field" formControlName="technologyInput" required> + <div class="input-selection"> + <input type="text" class="input-field" formControlName="technologyInput" required> + + <div class="input-errors"> + <label class="error">Type in your desired technologies, separated by a space</label> + </div> + </div> Available technologies: - <div *ngFor="let tech of availableTechnologies"> - {{ tech.name }} + <div id="all-technologies"> + <div class="user-technology" *ngFor="let tech of availableTechnologies"> + {{ tech.name }} + </div> </div> </div> - <button class="submit-btn" type="submit">Update profile</button> + <button id="update-profile-btn" class="submit-btn" type="submit">Update profile</button> <app-success-bar></app-success-bar> <app-error-bar></app-error-bar> </form> diff --git a/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.ts b/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.ts index 5be160e..e348b8b 100644 --- a/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.ts +++ b/src/DevHive.Angular/src/app/components/profile-settings/profile-settings.component.ts @@ -126,8 +126,8 @@ export class ProfileSettingsComponent implements OnInit { .then(value => this.updateUserFormGroup.patchValue({ technologyInput : value })); this.updateUserFormGroup.valueChanges.subscribe(() => { - this._successBar.hideMsg(); - this._errorBar.hideError(); + this._successBar?.hideMsg(); + this._errorBar?.hideError(); }); } @@ -185,7 +185,9 @@ export class ProfileSettingsComponent implements OnInit { // Transfer user input to objects of type { "name": "value" } const actualLanguages = []; for (const lName of names) { - actualLanguages.push({ name : lName }); + if (lName !== '') { + actualLanguages.push({ name : lName }); + } } // Add the data to the form (to the value that is going to be sent) @@ -211,7 +213,9 @@ export class ProfileSettingsComponent implements OnInit { // Transfer user input to objects of type { "name": "value" } const actualTechnologies = []; for (const tName of names) { - actualTechnologies.push({ name : tName }); + if (tName !== '') { + actualTechnologies.push({ name : tName }); + } } // Add the data to the form (to the value that is going to be sent) diff --git a/src/DevHive.Angular/src/app/components/profile/profile.component.css b/src/DevHive.Angular/src/app/components/profile/profile.component.css index 7d96624..f312ebd 100644 --- a/src/DevHive.Angular/src/app/components/profile/profile.component.css +++ b/src/DevHive.Angular/src/app/components/profile/profile.component.css @@ -74,16 +74,15 @@ hr { align-items: center; } -.user-language, .user-technology { - border-radius: .4em; - background-color: lightgrey; - padding: .2em; - margin: 0 .2em; -} - /* Posts */ -#posts { +#no-posts { width: 100%; + text-align: center; + color: gray; + margin-top: .2em; } +#posts { + width: 100%; +} diff --git a/src/DevHive.Angular/src/app/components/profile/profile.component.html b/src/DevHive.Angular/src/app/components/profile/profile.component.html index 43d580f..ac0c07e 100644 --- a/src/DevHive.Angular/src/app/components/profile/profile.component.html +++ b/src/DevHive.Angular/src/app/components/profile/profile.component.html @@ -41,9 +41,14 @@ None </div> </div> + <hr> <div id="posts"> - <hr> - Posts go here + <div id="no-posts" *ngIf="userPosts.length === 0"> + {{ user.firstName }} {{ user.lastName }} hasn't posted anything yet! + </div> + <div *ngFor="let userPost of userPosts"> + <app-post [paramId]="userPost.postId.toString()"></app-post> + </div> </div> </div> </div> diff --git a/src/DevHive.Angular/src/app/components/profile/profile.component.ts b/src/DevHive.Angular/src/app/components/profile/profile.component.ts index 69d7e72..7717505 100644 --- a/src/DevHive.Angular/src/app/components/profile/profile.component.ts +++ b/src/DevHive.Angular/src/app/components/profile/profile.component.ts @@ -7,6 +7,8 @@ import {HttpErrorResponse} from '@angular/common/http'; import {Location} from '@angular/common'; import {LanguageService} from 'src/app/services/language.service'; import {TechnologyService} from 'src/app/services/technology.service'; +import {Post} from 'src/models/post'; +import {FeedService} from 'src/app/services/feed.service'; @Component({ selector: 'app-profile', @@ -18,10 +20,11 @@ export class ProfileComponent implements OnInit { public loggedInUser = false; public dataArrived = false; public user: User; + public userPosts: Post[] = []; public showNoLangMsg = false; public showNoTechMsg = false; - constructor(private _router: Router, private _userService: UserService, private _languageService: LanguageService, private _technologyService: TechnologyService, private _location: Location) + constructor(private _router: Router, private _userService: UserService, private _languageService: LanguageService, private _technologyService: TechnologyService, private _feedService: FeedService, private _location: Location) { } private setDefaultUser(): void { @@ -57,19 +60,34 @@ export class ProfileComponent implements OnInit { private loadTechnologies(): void { if (this.user.technologies.length > 0) { - // When user has technologies, get their names and finally finish loading + // When user has technologies, get their names and then load posts this._technologyService.getFullTechnologiesFromIncomplete(this.user.technologies) .then(value => { this.user.technologies = value; - this.finishUserLoading(); + this.loadPosts(); }); } else { this.showNoTechMsg = true; - this.finishUserLoading(); + this.loadPosts(); } } + private loadPosts(): void { + const now = new Date(); + now.setHours(now.getHours() + 2); // accounting for eastern europe timezone + + this._feedService.getUserPostsRequest(this.user.userName, 1, now.toISOString(), AppConstants.PAGE_SIZE).subscribe( + (result: object) => { + this.userPosts = Object.values(result)[0]; + this.finishUserLoading(); + }, + (err: HttpErrorResponse) => { + this.finishUserLoading(); + } + ); + } + private finishUserLoading(): void { if (this.user.imageUrl === '') { this.user.imageUrl = AppConstants.FALLBACK_PROFILE_ICON; diff --git a/src/DevHive.Angular/src/app/components/success-bar/success-bar.component.ts b/src/DevHive.Angular/src/app/components/success-bar/success-bar.component.ts index 9a12c3a..f7db0e2 100644 --- a/src/DevHive.Angular/src/app/components/success-bar/success-bar.component.ts +++ b/src/DevHive.Angular/src/app/components/success-bar/success-bar.component.ts @@ -15,7 +15,10 @@ export class SuccessBarComponent implements OnInit { } showMsg(msg?: string | undefined): void { - if (msg === undefined || msg.trim() === '') { + if (msg === undefined) { + this.successMsg = 'Success!'; + } + else if (msg.trim() === '') { this.successMsg = 'Success!'; } else { diff --git a/src/DevHive.Angular/src/app/services/feed.service.ts b/src/DevHive.Angular/src/app/services/feed.service.ts new file mode 100644 index 0000000..cb82bcd --- /dev/null +++ b/src/DevHive.Angular/src/app/services/feed.service.ts @@ -0,0 +1,46 @@ +import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {Guid} from 'guid-typescript'; +import {Observable} from 'rxjs'; +import {IJWTPayload} from 'src/interfaces/jwt-payload'; +import {AppConstants} from '../app-constants.module'; +import jwt_decode from 'jwt-decode'; +import {IUserCredentials} from 'src/interfaces/user-credentials'; + +@Injectable({ + providedIn: 'root' +}) +export class FeedService { + constructor(private http: HttpClient) { } + + getUserFeedFromSessionStorageRequest(pageNumber: number, firstTimeIssued: string, pageSize: number): Observable<object> { + const jwt: IJWTPayload = { token: sessionStorage.getItem('UserCred') ?? '' }; + const userCred = jwt_decode<IUserCredentials>(jwt.token); + return this.getUserFeedRequest(userCred.ID, jwt.token, pageNumber, firstTimeIssued, pageSize); + } + + getUserFeedRequest(userId: Guid, authToken: string, pageNumber: number, firstTimeIssued: string, pageSize: number): Observable<object> { + const body = { + pageNumber: pageNumber, + firstPageTimeIssued: firstTimeIssued, + pageSize: pageSize + }; + const options = { + params: new HttpParams().set('UserId', userId.toString()), + headers: new HttpHeaders().set('Authorization', 'Bearer ' + authToken) + }; + return this.http.post(AppConstants.API_FEED_URL + '/GetPosts', body, options); + } + + getUserPostsRequest(userName: string, pageNumber: number, firstTimeIssued: string, pageSize: number): Observable<object> { + const body = { + pageNumber: pageNumber, + firstPageTimeIssued: firstTimeIssued, + pageSize: pageSize + }; + const options = { + params: new HttpParams().set('UserName', userName) + }; + return this.http.post(AppConstants.API_FEED_URL + '/GetUserPosts', body, options); + } +} diff --git a/src/DevHive.Angular/src/app/services/post.service.ts b/src/DevHive.Angular/src/app/services/post.service.ts new file mode 100644 index 0000000..4cd96bc --- /dev/null +++ b/src/DevHive.Angular/src/app/services/post.service.ts @@ -0,0 +1,25 @@ +import {HttpClient, HttpParams} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {Guid} from 'guid-typescript'; +import {Observable} from 'rxjs'; +import {Post} from 'src/models/post'; +import {AppConstants} from '../app-constants.module'; + +@Injectable({ + providedIn: 'root' +}) +export class PostService { + constructor(private http: HttpClient) { } + + getDefaultPost(): Post { + return new Post(Guid.createEmpty(), 'Gosho', 'Trapov', 'gosho_trapov', 'Your opinion on my idea?', new Date()); + } + + getPostRequest(id: Guid): Observable<object> { + const options = { + params: new HttpParams().set('Id', id.toString()) + }; + return this.http.get(AppConstants.API_POST_URL, options); + } +} + diff --git a/src/DevHive.Angular/src/models/post.ts b/src/DevHive.Angular/src/models/post.ts new file mode 100644 index 0000000..2d7d79f --- /dev/null +++ b/src/DevHive.Angular/src/models/post.ts @@ -0,0 +1,63 @@ +import {Guid} from 'guid-typescript'; + +export class Post { + private _postId: Guid; + private _creatorFirstName: string; + private _creatorLastName: string; + private _creatorUsername: string; + private _message: string; + private _timeCreated: Date; + // _comments + // _files + + constructor(postId: Guid, creatorFirstName: string, creatorLastName: string, creatorUsername: string, message: string, timeCreated: Date) { + this.postId = postId; + this.creatorFirstName = creatorFirstName; + this.creatorLastName = creatorLastName; + this.creatorUsername = creatorUsername; + this.message = message; + this.timeCreated = timeCreated; + } + + public get postId(): Guid { + return this._postId; + } + public set postId(v: Guid) { + this._postId = v; + } + + public get creatorFirstName(): string { + return this._creatorFirstName; + } + public set creatorFirstName(v: string) { + this._creatorFirstName = v; + } + + public get creatorLastName(): string { + return this._creatorLastName; + } + public set creatorLastName(v: string) { + this._creatorLastName = v; + } + + public get creatorUsername(): string { + return this._creatorUsername; + } + public set creatorUsername(v: string) { + this._creatorUsername = v; + } + + public get message(): string { + return this._message; + } + public set message(v: string) { + this._message = v; + } + + public get timeCreated(): Date { + return this._timeCreated; + } + public set timeCreated(v: Date) { + this._timeCreated = v; + } +} diff --git a/src/DevHive.Angular/src/styles.css b/src/DevHive.Angular/src/styles.css index 1320795..aaa1bd5 100644 --- a/src/DevHive.Angular/src/styles.css +++ b/src/DevHive.Angular/src/styles.css @@ -73,6 +73,13 @@ input:focus, button:focus { scrollbar-width: none; /* Firefox */ } +.user-language, .user-technology { + border-radius: .4em; + background-color: lightgrey; + padding: .26em; + margin: 0 .2em; +} + /* Inputs, the type found in login and register */ .input-selection { |
