diff options
Diffstat (limited to 'src/app/components/feed')
| -rw-r--r-- | src/app/components/feed/feed.component.css | 179 | ||||
| -rw-r--r-- | src/app/components/feed/feed.component.html | 52 | ||||
| -rw-r--r-- | src/app/components/feed/feed.component.ts | 122 |
3 files changed, 353 insertions, 0 deletions
diff --git a/src/app/components/feed/feed.component.css b/src/app/components/feed/feed.component.css new file mode 100644 index 0000000..cb155c6 --- /dev/null +++ b/src/app/components/feed/feed.component.css @@ -0,0 +1,179 @@ +#feed-page { + height: 100%; + max-width: 40em; + box-sizing: border-box; + border: .5em solid var(--bg-color); + + margin: 0 auto; + + display: flex; +} + +@media screen and (max-width: 750px) { + #profile-bar { + display: none !important; + } + #top-bar-profile-pic { + display: initial; + } +} +@media screen and (min-width: 750px) { + #profile-bar { + display: initial; + } + #top-bar-profile-pic { + display: none !important; + } +} + +/* Content */ + +#feed-content { + flex: 1; + display: flex; + flex-direction: column; +} + +/* Profile bar */ + +#profile-bar { + width: 20%; + height: fit-content; + display: flex; + flex-direction: column; + align-items: center; + + box-sizing: border-box; + background-color: var(--bg-color); + + margin-right: .5em; + padding-bottom: 1em; + padding: .5em; + border-radius: .6em; +} + +#profile-bar-profile-pic { + width: 7em; + height: 7em; + box-sizing: border-box; + padding: .5em; +} + +#profile-bar-name { + text-align: center; +} + +#profile-bar-username { + margin: .5em 0; +} + +#profile-bar > #profile-info { + display: flex; + flex-direction: column; + align-items: center; +} + +/* Top bar */ + +#top-bar { + display: flex; + flex-direction: column; + width: 98%; + margin: 0 auto; + margin-bottom: .5em; + box-sizing: border-box; +} + +#top-bar-profile-pic { + height: 2.5em; + width: 2.5em; + margin-right: .5em; +} + +#top-bar-profile-pic > img { + height: inherit; + width: inherit; +} + +#top-bar-open-chat { + /* Until implemented */ + display: none; +} + +#main-content { + display: flex; +} + +/* Create post */ + +#create-post-form { + width: 100%; + position: relative; + display: flex; + flex-direction: column; + box-sizing: border-box; +} + +#form-inputs { + display: flex; +} + +#top-bar-create-post { + flex: 1; + font-size: inherit; + width: 100%; + height: 100%; + margin: 0 auto; + box-sizing: border-box; + border: 2px solid var(--bg-color); + border-radius: .6em; +} + +#file-upload { + font-size: inherit; + color: transparent; + width: 1.5em; + height: 1.5em; +} + +#file-upload:hover { + cursor: pointer; +} + +#file-upload::-webkit-file-upload-button { + visibility: hidden; +} + +#attachment-img { + height: 1.5em; + width: 1.5em; + position: absolute; + right: .4em; + pointer-events: 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, +#top-bar-profile-pic:hover { + cursor: pointer; +} + +/* Can't copy text from */ + +#profile-bar, +.vote { + -webkit-user-select: none; /* Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+/Edge */ + user-select: none; /* Standard */ +} diff --git a/src/app/components/feed/feed.component.html b/src/app/components/feed/feed.component.html new file mode 100644 index 0000000..1a03dcc --- /dev/null +++ b/src/app/components/feed/feed.component.html @@ -0,0 +1,52 @@ +<app-loading *ngIf="!dataArrived"></app-loading> + +<div id="feed-page" *ngIf="dataArrived"> + <nav id="profile-bar" class="round-image rounded-border"> + <div id="profile-info" (click)="goToProfile()"> + <img id="profile-bar-profile-pic" class="round-image" [src]="user.profilePictureURL" alt=""/> + <div id="profile-bar-name"> + {{ user.firstName }} {{ user.lastName }} + </div> + <div id="profile-bar-username"> + @{{ user.userName }} + </div> + </div> + <button class="submit-btn" (click)="goToSettings()">Settings</button> + <button class="submit-btn" (click)="logout()">Logout</button> + </nav> + <div id="feed-content"> + <nav id="top-bar"> + <div id="main-content"> + <img id="top-bar-profile-pic" class="round-image" [src]="user.profilePictureURL" alt="" (click)="goToProfile()"> + <form id="create-post-form" class="rounded-border" [formGroup]="createPostFormGroup" (ngSubmit)="createPost()"> + <div id="form-inputs"> + <input id="top-bar-create-post" type="text" formControlName="newPostMessage" placeholder="What's on your mind?"/> + <input type="submit" style="display: none" /> <!-- You need this element, so when you press enter the request is sent --> + <img id="attachment-img" src="assets/images/paper-clip.png"> + <input id="file-upload" type="file" formControlName="fileUpload" (change)="onFileUpload($event)" multiple> + </div> + <div class="form-attachments"> + <div *ngFor="let file of files" class="form-attachment"> + {{ file.name ? file.name : 'Attachment' }} + <div class="remove-form-attachment" (click)="removeAttachment(file.name)"> + ☒ + </div> + </div> + </div> + </form> + <a id="top-bar-open-chat" href=""> + <img src="assets/images/feed/chat-pic.png" alt=""/> + </a> + </div> + </nav> + <div id="posts" class="scroll-standalone" (scroll)="onScroll($event)"> + <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> +</div> diff --git a/src/app/components/feed/feed.component.ts b/src/app/components/feed/feed.component.ts new file mode 100644 index 0000000..b412b3c --- /dev/null +++ b/src/app/components/feed/feed.component.ts @@ -0,0 +1,122 @@ +import { Component, OnInit } from '@angular/core'; +import { Title } from '@angular/platform-browser'; +import { Router } from '@angular/router'; +import { User } from 'src/models/identity/user'; +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'; +import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; +import { PostService } from 'src/app/services/post.service'; +import { TokenService } from 'src/app/services/token.service'; + +@Component({ + selector: 'app-feed', + templateUrl: './feed.component.html', + styleUrls: ['./feed.component.css'] +}) +export class FeedComponent implements OnInit { + private _title = 'Feed'; + private _timeLoaded: string; // we send the time to the api as a string + private _currentPage: number; + public dataArrived = false; + public user: User; + public posts: Post[]; + public createPostFormGroup: FormGroup; + public files: File[]; + + constructor(private _titleService: Title, private _fb: FormBuilder, private _router: Router, private _userService: UserService, private _feedService: FeedService, private _postService: PostService, private _tokenService: TokenService) { + this._titleService.setTitle(this._title); + } + + ngOnInit(): void { + if (!this._tokenService.getTokenFromSessionStorage()) { + this._router.navigate(['/login']); + return; + } + + this._currentPage = 1; + this.posts = []; + this.user = this._userService.getDefaultUser(); + this.files = []; + + const now = new Date(); + now.setHours(now.getHours() + 2); // accounting for eastern european timezone + this._timeLoaded = now.toISOString(); + + this.createPostFormGroup = this._fb.group({ + newPostMessage: new FormControl(''), + fileUpload: new FormControl('') + }); + + this._userService.getUserFromSessionStorageRequest().subscribe( + (res: object) => { + Object.assign(this.user, res); + this.loadFeed(); + }, + (err: HttpErrorResponse) => { + this.logout(); + } + ); + } + + private loadFeed(): void { + this._feedService.getUserFeedFromSessionStorageRequest(this._currentPage++, this._timeLoaded, AppConstants.PAGE_SIZE).subscribe( + (result: object) => { + this.posts.push(...Object.values(result)[0]); + this.finishUserLoading(); + }, + (err) => { + this.finishUserLoading(); + } + ); + } + + private finishUserLoading(): void { + this.dataArrived = true; + } + + goToProfile(): void { + this._router.navigate(['/profile/' + this.user.userName]); + } + + goToSettings(): void { + this._router.navigate(['/profile/' + this.user.userName + '/settings']); + } + + logout(): void { + this._tokenService.logoutUserFromSessionStorage(); + this._router.navigate(['/login']); + } + + onFileUpload(event: any): void { + this.files.push(...event.target.files); + this.createPostFormGroup.get('fileUpload')?.reset(); + } + + removeAttachment(fileName: string): void { + this.files = this.files.filter(x => x.name !== fileName); + } + + createPost(): void { + const postMessage = this.createPostFormGroup.get('newPostMessage')?.value; + this.dataArrived = false; + + this._postService.createPostWithSessionStorageRequest(postMessage, this.files).subscribe( + (result: object) => { + this.goToProfile(); + }, + (err: HttpErrorResponse) => { + this.dataArrived = true; + } + ); + } + + onScroll(event: any): void { + // Detects when the element has reached the bottom, thx https://stackoverflow.com/a/50038429/12036073 + if (event.target.offsetHeight + event.target.scrollTop >= event.target.scrollHeight && this._currentPage > 0) { + this.loadFeed(); + } + } +} |
