diff --git a/src/app/components/feed/feed.component.html b/src/app/components/feed/feed.component.html index fca185c..00f4bbb 100644 --- a/src/app/components/feed/feed.component.html +++ b/src/app/components/feed/feed.component.html @@ -6,30 +6,45 @@
-
-

Preview:

- - +
+

Preview:

+
+ + + +
- - - - - -

- I protected the environment. - -

+
+
What did you do? - + nothing ;) @@ -38,7 +53,8 @@ {{getErrorMessage()}} - diff --git a/src/app/components/feed/feed.component.sass b/src/app/components/feed/feed.component.sass index 5f16e08..7d6390b 100644 --- a/src/app/components/feed/feed.component.sass +++ b/src/app/components/feed/feed.component.sass @@ -27,23 +27,26 @@ #feedlist width: 100% -#input +.input width: 100% padding-left: 0.5em padding-right: 0.5em - .mat-icon - transform: scale(1.5) +.left, .right + display: inline-block + width: 50% +.left + text-align: left +.right + text-align: right #inputPreview - max-width: 75% - max-height: 100% + max-width: 100% + max-height: 45vh width: auto border-radius: 4px mask-mode: luminance outline: none user-select: none ::ng-deep video - width: 100% - max-height: 40vh outline: none user-select: none #inputPreviewWrapper @@ -51,6 +54,19 @@ text-align: center max-height: 512px margin-bottom: 1em + #media-box + position: relative + width: 100% +::ng-deep .light-theme .discard-button + margin: 0.5em + position: absolute + background: hsla(255,100%,100%,0.3) +::ng-deep .dark-theme .discard-button + margin: 0.5em + position: absolute + background: hsla(0,0%,0%,0.3) +#progress-bar + margin-top: 1em #action-chooser width: 100% @@ -60,6 +76,10 @@ #check margin: 0 padding-left: 0.5em + display: contents +#button-box + text-align: right + margin-left: auto #post-button width: 100% diff --git a/src/app/components/feed/feed.component.ts b/src/app/components/feed/feed.component.ts index d226149..abb2992 100644 --- a/src/app/components/feed/feed.component.ts +++ b/src/app/components/feed/feed.component.ts @@ -1,4 +1,4 @@ -import {Component, OnInit} from '@angular/core'; +import {Component, OnInit, ViewChild, ElementRef} from '@angular/core'; import {Post} from 'src/app/models/post'; import {FeedService, Sort} from 'src/app/services/feed/feed.service'; import {Activitylist} from 'src/app/models/activity'; @@ -17,11 +17,13 @@ export class FeedComponent implements OnInit { loadingNew = true; loadingMostLiked = true; // file upload variables + @ViewChild('fileInput', {static: false}) fileInput: ElementRef; public uploading = false; public profilePictureUrl: BehaviorSubject; private file; fileType; public localFileUrl; + posting = false; checked = false; // if the "I protected the environment."-box is checked view = 'new'; @@ -61,6 +63,13 @@ export class FeedComponent implements OnInit { this.feedService.postsAvailable.subscribe(available => { this.loadingMostLiked = this.loadingNew = available; }); + this.feedService.posting.subscribe(posting => { + const temp = this.posting; + this.posting = posting; + if (temp !== this.posting && !this.posting) { + this.resetPostInput(); + } + }); } /** @@ -70,38 +79,41 @@ export class FeedComponent implements OnInit { */ createPost(postElement, activityId: string) { if (postElement && activityId && this.checked) { + this.posting = true; this.feedService.createPostActivity(postElement.value, activityId, this.file).subscribe(() => { - postElement.value = ''; - this.textInputValue = ''; - this.checked = false; - this.file = null; - this.localFileUrl = null; - this.fileType = null; - if (this.view !== 'new') { - this.showNew(); - } }, (error: IErrorResponse) => { this.errorOccurred = true; + this.posting = false; this.errorMessage = error.error.errors[0].message; }); } else if (postElement) { - this.feedService.createPost(postElement.value, this.file).subscribe(() => { - postElement.value = ''; - this.textInputValue = ''; - this.checked = false; - this.file = null; - this.localFileUrl = null; - this.fileType = null; - if (this.view !== 'new') { - this.showNew(); - } + this.posting = true; + this.feedService.createPost(postElement.value, this.file).subscribe((result) => { }, (error: IErrorResponse) => { + console.log(error); + this.posting = false; this.errorOccurred = true; this.errorMessage = error.error.errors[0].message; }); } } + discardFile() { + this.file = null; + this.localFileUrl = null; + this.fileType = null; + this.fileInput.nativeElement.value = ''; + } + + resetPostInput() { + this.textInputValue = ''; + this.checked = false; + this.discardFile(); + if (this.view !== 'new') { + this.showNew(); + } + } + onFileInputChange(event) { this.errorOccurred = false; this.errorMessage = ''; @@ -119,7 +131,7 @@ export class FeedComponent implements OnInit { } /** - * Fetches the next posts when scrolled + * Fetches the next posts when scrolled down */ onScroll() { this.feedService.getNextPosts(); diff --git a/src/app/components/feed/postlist/postlist.component.html b/src/app/components/feed/postlist/postlist.component.html index 50f13eb..f07a137 100644 --- a/src/app/components/feed/postlist/postlist.component.html +++ b/src/app/components/feed/postlist/postlist.component.html @@ -22,8 +22,11 @@ +
- post image +
+ post image +
diff --git a/src/app/components/feed/postlist/postlist.component.sass b/src/app/components/feed/postlist/postlist.component.sass index d27fcd9..3f2c0a4 100644 --- a/src/app/components/feed/postlist/postlist.component.sass +++ b/src/app/components/feed/postlist/postlist.component.sass @@ -60,16 +60,19 @@ $mat-card-header-size: 40px !default display: block margin-left: auto margin-right: auto + margin-bottom: 0.5em ::ng-deep video width: 100% max-height: 40vh outline: none user-select: none + margin-bottom: 0.5em ::ng-deep audio width: 100% max-height: 40vh outline: none user-select: none + margin-bottom: 0.5em .mat-button min-width: 32px !important diff --git a/src/app/components/feed/postlist/postlist.component.ts b/src/app/components/feed/postlist/postlist.component.ts index 4112719..84e2044 100644 --- a/src/app/components/feed/postlist/postlist.component.ts +++ b/src/app/components/feed/postlist/postlist.component.ts @@ -49,6 +49,10 @@ export class PostlistComponent implements OnInit { }); } + onLoad(post: Post) { + post.mediaLoading = false; + } + public showUserProfile(post: any) { this.router.navigate(['profile/' + post.author.id]); } diff --git a/src/app/components/group/group.component.sass b/src/app/components/group/group.component.sass index 6312e7b..6046785 100644 --- a/src/app/components/group/group.component.sass +++ b/src/app/components/group/group.component.sass @@ -54,7 +54,7 @@ $mat-card-header-size: 100px !default #icon display: none position: absolute - z-index: 11 + z-index: 100 color: white $mat-card-header-size: 100px !default diff --git a/src/app/components/social/friends/friends.component.html b/src/app/components/social/friends/friends.component.html index c036f75..9d011ec 100644 --- a/src/app/components/social/friends/friends.component.html +++ b/src/app/components/social/friends/friends.component.html @@ -17,7 +17,7 @@
-
+
{{friend.name}} diff --git a/src/app/models/post.ts b/src/app/models/post.ts index 3143140..91fff08 100644 --- a/src/app/models/post.ts +++ b/src/app/models/post.ts @@ -1,5 +1,6 @@ import {Author} from './author'; import {Activity} from './activity'; +import { environment } from 'src/environments/environment'; export class Post { id: number; @@ -12,6 +13,7 @@ export class Post { deletable: boolean; author: Author; activity: Activity; + mediaLoading: boolean; mediaUrl: string; mediaType: 'VIDEO' | 'IMAGE'; @@ -39,8 +41,9 @@ export class Post { this.author = author; this.activity = activity; if (media) { - this.mediaUrl = media.url; + this.mediaUrl = environment.greenvironmentUrl + media.url; this.mediaType = media.type; + this.mediaLoading = true; } } } diff --git a/src/app/services/feed/feed.service.ts b/src/app/services/feed/feed.service.ts index 3c924fd..9f0a8fd 100644 --- a/src/app/services/feed/feed.service.ts +++ b/src/app/services/feed/feed.service.ts @@ -10,8 +10,8 @@ import {BaseService} from '../base.service'; import {formatDate} from '@angular/common'; import {IFileUploadResult} from '../../models/interfaces/IFileUploadResult'; -const createPostGqlQuery = `mutation($content: String!) { - createPost(content: $content) { +const createPostGqlQuery = `mutation($content: String!, $type: PostType) { + createPost(content: $content, type: $type) { id, content, htmlContent, @@ -34,8 +34,8 @@ const createPostGqlQuery = `mutation($content: String!) { createdAt} }`; -const createPostActivityGqlQuery = `mutation($content: String!, $id: ID) { - createPost(content: $content activityId: $id) { +const createPostActivityGqlQuery = `mutation($content: String!, $id: ID, $type: PostType) { + createPost(content: $content activityId: $id, type: $type) { id, content, htmlContent, @@ -70,7 +70,7 @@ const downvotePostGqlQuery = `mutation($postId: ID!) { } }`; -const getPostGqlQuery = `query($first: Int, $offset: Int, $sort: SortType){ +const getPostsGqlQuery = `query($first: Int, $offset: Int, $sort: SortType){ getPosts (first: $first, offset: $offset, sort: $sort) { id, content, @@ -109,6 +109,7 @@ export class FeedService extends BaseService { } public postsAvailable = new BehaviorSubject(true); + public posting = new BehaviorSubject(false); public posts: BehaviorSubject = new BehaviorSubject([]); private activePostList: Sort = Sort.NEW; private offset = 0; @@ -122,7 +123,7 @@ export class FeedService extends BaseService { */ private static buildGetPostBody(sort: string, offset: number, first: number = 10) { return { - query: getPostGqlQuery, variables: { + query: getPostsGqlQuery, variables: { first, offset, sort @@ -145,10 +146,15 @@ export class FeedService extends BaseService { * @param file */ public createPost(pContent: String, file?: File) { + let type: string; + if (file) { type = 'MEDIA'; } else { + type = 'TEXT'; + } const body = { query: createPostGqlQuery, variables: { - content: pContent + content: pContent, + type } }; return this.createPostRequest(body, file); @@ -161,10 +167,15 @@ export class FeedService extends BaseService { * @param file */ public createPostActivity(pContent: String, activityId: String, file?: File) { + let type: string; + if (file) { type = 'MEDIA'; } else { + type = 'TEXT'; + } const body = { query: createPostActivityGqlQuery, variables: { content: pContent, - id: activityId + id: activityId, + type } }; return this.createPostRequest(body, file); @@ -176,26 +187,39 @@ export class FeedService extends BaseService { * @param file - a file that is being uploaded with the post */ private createPostRequest(body: { variables: any; query: string }, file?: File) { - return this.postGraphql(body, null, 0) + this.posting.next(true); + if (file) { + return this.postGraphql(body, null, 0) + .pipe(tap(response => { + const updatedPosts = this.posts.getValue(); + const post = this.constructPost(response); + this.uploadPostImage(post.id, file).subscribe((result) => { + if (this.activePostList === Sort.NEW) { + post.mediaUrl = result.fileName; + post.mediaType = result.fileName.endsWith('.png') ? 'IMAGE' : 'VIDEO'; + updatedPosts.unshift(post); + this.posts.next(updatedPosts); + this.posting.next(false); + } + }, error => { + console.error(error); + this.posting.next(false); + this.deletePost(post.id); + }); + } + )); + } else if (!file) { + return this.postGraphql(body, null, 0) .pipe(tap(response => { + this.posting.next(false); + const updatedPosts = this.posts.getValue(); if (this.activePostList === Sort.NEW) { - const updatedPosts = this.posts.getValue(); const post = this.constructPost(response); updatedPosts.unshift(post); - if (file) { - this.uploadPostImage(post.id, file).subscribe((result) => { - post.mediaUrl = result.fileName; - post.mediaType = result.fileName.endsWith('.png') ? 'IMAGE' : 'VIDEO'; - this.posts.next(updatedPosts); - }, error => { - console.error(error); - this.deletePost(post.id); - }); - } else { - this.posts.next(updatedPosts); - } + this.posts.next(updatedPosts); } })); + } } /** @@ -266,7 +290,7 @@ export class FeedService extends BaseService { {headers: this.headers}) .pipe(this.retryRated()) .subscribe(response => { - this.posts.next(this.constructAllPosts(response)); + this.posts.next(this.constructAllPosts(response.data.getPosts)); this.activePostList = sort; }); } @@ -280,7 +304,7 @@ export class FeedService extends BaseService { this.http.post(environment.graphQLUrl, body, {headers: this.headers}) .pipe(this.retryRated()) .subscribe(response => { - const posts = this.constructAllPosts(response); + const posts = this.constructAllPosts(response.data.getPosts); const previousPosts = this.posts.getValue(); for (const post of previousPosts.reverse()) { if (!posts.find(p => p.id === post.id)) { @@ -337,7 +361,7 @@ export class FeedService extends BaseService { public constructAllPosts(response: any): Post[] { const posts = new Array(); - for (const post of response.data.getPosts) { + for (const post of response) { let profilePicture: string; if (post.author.profilePicture) { profilePicture = environment.greenvironmentUrl + post.author.profilePicture; diff --git a/src/app/services/profile/profile.service.ts b/src/app/services/profile/profile.service.ts index 809cb71..a808a16 100644 --- a/src/app/services/profile/profile.service.ts +++ b/src/app/services/profile/profile.service.ts @@ -7,6 +7,7 @@ import {User} from 'src/app/models/user'; import {Subject} from 'rxjs'; import {Activity} from 'src/app/models/activity'; import {BaseService} from '../base.service'; +import {FeedService} from 'src/app/services/feed/feed.service'; const graphqlGetProfileQuery = `query($userId: ID) { getUser(userId:$userId){ @@ -30,6 +31,7 @@ const graphqlGetProfileQuery = `query($userId: ID) { downvotes, userVote, deletable, + media {url, type}, activity{ id name @@ -39,7 +41,7 @@ const graphqlGetProfileQuery = `query($userId: ID) { author{ name, handle, - profilePicture + profilePicture, id}, createdAt } @@ -51,7 +53,7 @@ const graphqlGetProfileQuery = `query($userId: ID) { }) export class ProfileService extends BaseService { - constructor(http: HttpClient) { + constructor(http: HttpClient, private feedService: FeedService) { super(http); } @@ -96,38 +98,7 @@ export class ProfileService extends BaseService { const temp = new Date(Number(response.data.getUser.joinedAt)); const date = temp.toLocaleString('en-GB'); profile.joinedAt = date; - for (const post of response.data.getUser.posts) { - const id: number = post.id; - const content: string = post.content; - const htmlContent: string = post.htmlContent; - const upvotes: number = post.upvotes; - const downvotes: number = post.downvotes; - const userVote: string = post.userVote; - const deletable: boolean = post.deletable; - let profilePicture: string; - if (post.author.profilePicture) { - profilePicture = environment.greenvironmentUrl + post.author.profilePicture; - } else { - profilePicture = 'assets/images/default-profilepic.svg'; - } - const author = new Author(post.author.id, post.author.name, post.author.handle, profilePicture); - const ptemp = new Date(Number(post.createdAt)); - const pdate = ptemp.toLocaleString('en-GB'); - let activity: Activity; - if (post.activity) { - activity = new Activity( - post.activity.id, - post.activity.name, - post.activity.description, - post.activity.points); - } else { - activity = null; - } - - // tslint:disable-next-line: max-line-length - posts.push(new Post(id, content, htmlContent, upvotes, downvotes, userVote, deletable, pdate, author, activity)); - } - profile.posts = posts; + profile.posts = this.feedService.constructAllPosts(response.data.getUser.posts); return profile; } return null;