Merge branch 'max_dev' of Software_Engineering_I/greenvironment-frontend into master

master
Max_ES 5 years ago committed by Gitea
commit 2bcd1f3fbc

@ -6,30 +6,45 @@
<div [hidden]="!loggedIn"> <div [hidden]="!loggedIn">
<mat-card> <mat-card>
<mat-card-content> <mat-card-content>
<div id="inputPreviewWrapper"> <div id="inputPreviewWrapper" *ngIf="localFileUrl">
<h2 *ngIf="localFileUrl">Preview:</h2> <h2>Preview:</h2>
<div id="media-box">
<button class="discard-button" mat-button mat-icon-button (click)="discardFile()"
matTooltip="discard file"
matTooltipShowDelay="200"
[disabled]="posting">
<mat-icon>close</mat-icon>
</button>
<img *ngIf="fileType == 'image'" id="inputPreview" [src]="localFileUrl"/> <img *ngIf="fileType == 'image'" id="inputPreview" [src]="localFileUrl"/>
<video *ngIf="fileType == 'video'" [src]="localFileUrl" controls="" class="html5-video-player"> <video *ngIf="fileType == 'video'" [src]="localFileUrl" id="inputPreview" controls="" class="html5-video-player">
Your browser does not support playing HTML5 video. Your browser does not support playing HTML5 video.
</video> </video>
</div> </div>
<mat-form-field id="input"> </div>
<textarea matInput #content type="text" (input)="onTextInputChange()" [(ngModel)]="textInputValue" <mat-form-field class="input">
<textarea matInput #content type="text" (input)="onTextInputChange()" [(ngModel)]="textInputValue" [disabled]="posting"
mat-autosize="true" matAutosizeMaxRows="3" placeholder="post something"></textarea> mat-autosize="true" matAutosizeMaxRows="3" placeholder="post something"></textarea>
<button mat-button matSuffix mat-icon-button (click)="name.click()"
matTooltip="upload a picture or video (up to 10MB)"
matTooltipShowDelay="200">
<mat-icon>attach_file</mat-icon>
</button>
<input style="display: none" id="input-file" type="file" accept="video/*,image/*" (change)="onFileInputChange($event)" #name>
</mat-form-field> </mat-form-field>
<input style="display: none" id="input-file" type="file" accept="video/*,image/*" (change)="onFileInputChange($event)" #name>
<div class="input">
<div class="left">
<p id="check"> <p id="check">
<mat-checkbox color="primary" [(ngModel)]="checked" checked="checked">I protected the environment. <mat-checkbox color="primary" [(ngModel)]="checked" checked="checked" [disabled]="posting">I protected the environment.
</mat-checkbox> </mat-checkbox>
</p> </p>
</div>
<div class="right">
<button mat-button mat-icon-button (click)="name.click()"
matTooltip="upload a picture or video (up to 10MB)"
matTooltipShowDelay="200"
[disabled]="posting">
<mat-icon>attach_file</mat-icon>
</button>
</div>
</div>
<mat-form-field id="action-chooser" *ngIf="checked"> <mat-form-field id="action-chooser" *ngIf="checked">
<mat-label>What did you do?</mat-label> <mat-label>What did you do?</mat-label>
<mat-select [(ngModel)]="activityId" name="action"> <mat-select [(ngModel)]="activityId" name="action" [disabled]="posting">
<mat-option>nothing ;)</mat-option> <mat-option>nothing ;)</mat-option>
<mat-option *ngFor="let action of actionlist.Actions" [value]="action.id" [matTooltip]="action.description" <mat-option *ngFor="let action of actionlist.Actions" [value]="action.id" [matTooltip]="action.description"
matTooltipShowDelay="200"> matTooltipShowDelay="200">
@ -38,7 +53,8 @@
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-error *ngIf="errorOccurred && textInputValue">{{getErrorMessage()}}</mat-error> <mat-error *ngIf="errorOccurred && textInputValue">{{getErrorMessage()}}</mat-error>
<button mat-raised-button *ngIf="textInputValue" color="primary" id="post-button" <mat-progress-bar id="progress-bar" *ngIf="posting" mode="indeterminate"></mat-progress-bar>
<button mat-raised-button *ngIf="textInputValue" color="primary" id="post-button" [disabled]="posting"
(click)=createPost(content,activityId)> (click)=createPost(content,activityId)>
POST POST
</button> </button>

@ -27,23 +27,26 @@
#feedlist #feedlist
width: 100% width: 100%
#input .input
width: 100% width: 100%
padding-left: 0.5em padding-left: 0.5em
padding-right: 0.5em padding-right: 0.5em
.mat-icon .left, .right
transform: scale(1.5) display: inline-block
width: 50%
.left
text-align: left
.right
text-align: right
#inputPreview #inputPreview
max-width: 75% max-width: 100%
max-height: 100% max-height: 45vh
width: auto width: auto
border-radius: 4px border-radius: 4px
mask-mode: luminance mask-mode: luminance
outline: none outline: none
user-select: none user-select: none
::ng-deep video ::ng-deep video
width: 100%
max-height: 40vh
outline: none outline: none
user-select: none user-select: none
#inputPreviewWrapper #inputPreviewWrapper
@ -51,6 +54,19 @@
text-align: center text-align: center
max-height: 512px max-height: 512px
margin-bottom: 1em 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 #action-chooser
width: 100% width: 100%
@ -60,6 +76,10 @@
#check #check
margin: 0 margin: 0
padding-left: 0.5em padding-left: 0.5em
display: contents
#button-box
text-align: right
margin-left: auto
#post-button #post-button
width: 100% width: 100%

@ -1,4 +1,4 @@
import {Component, OnInit} from '@angular/core'; import {Component, OnInit, ViewChild} from '@angular/core';
import {Post} from 'src/app/models/post'; import {Post} from 'src/app/models/post';
import {FeedService, Sort} from 'src/app/services/feed/feed.service'; import {FeedService, Sort} from 'src/app/services/feed/feed.service';
import {Activitylist} from 'src/app/models/activity'; import {Activitylist} from 'src/app/models/activity';
@ -17,11 +17,13 @@ export class FeedComponent implements OnInit {
loadingNew = true; loadingNew = true;
loadingMostLiked = true; loadingMostLiked = true;
// file upload variables // file upload variables
@ViewChild('name', {static: false}) fileInput;
public uploading = false; public uploading = false;
public profilePictureUrl: BehaviorSubject<string | null>; public profilePictureUrl: BehaviorSubject<string | null>;
private file; private file;
fileType; fileType;
public localFileUrl; public localFileUrl;
posting = false;
checked = false; // if the "I protected the environment."-box is checked checked = false; // if the "I protected the environment."-box is checked
view = 'new'; view = 'new';
@ -70,7 +72,9 @@ export class FeedComponent implements OnInit {
*/ */
createPost(postElement, activityId: string) { createPost(postElement, activityId: string) {
if (postElement && activityId && this.checked) { if (postElement && activityId && this.checked) {
this.posting = true;
this.feedService.createPostActivity(postElement.value, activityId, this.file).subscribe(() => { this.feedService.createPostActivity(postElement.value, activityId, this.file).subscribe(() => {
this.posting = false;
postElement.value = ''; postElement.value = '';
this.textInputValue = ''; this.textInputValue = '';
this.checked = false; this.checked = false;
@ -81,11 +85,15 @@ export class FeedComponent implements OnInit {
this.showNew(); this.showNew();
} }
}, (error: IErrorResponse) => { }, (error: IErrorResponse) => {
this.posting = false;
this.errorOccurred = true; this.errorOccurred = true;
this.errorMessage = error.error.errors[0].message; this.errorMessage = error.error.errors[0].message;
}); });
} else if (postElement) { } else if (postElement) {
this.feedService.createPost(postElement.value, this.file).subscribe(() => { this.posting = true;
this.feedService.createPost(postElement.value, this.file).subscribe((result) => {
console.log('response in component');
this.posting = false;
postElement.value = ''; postElement.value = '';
this.textInputValue = ''; this.textInputValue = '';
this.checked = false; this.checked = false;
@ -96,12 +104,22 @@ export class FeedComponent implements OnInit {
this.showNew(); this.showNew();
} }
}, (error: IErrorResponse) => { }, (error: IErrorResponse) => {
console.log('an error occured in component');
console.log(error);
this.posting = false;
this.errorOccurred = true; this.errorOccurred = true;
this.errorMessage = error.error.errors[0].message; this.errorMessage = error.error.errors[0].message;
}); });
} }
} }
discardFile() {
this.file = null;
this.localFileUrl = null;
this.fileType = null;
this.fileInput.nativeElement.value = '';
}
onFileInputChange(event) { onFileInputChange(event) {
this.errorOccurred = false; this.errorOccurred = false;
this.errorMessage = ''; this.errorMessage = '';
@ -119,7 +137,7 @@ export class FeedComponent implements OnInit {
} }
/** /**
* Fetches the next posts when scrolled * Fetches the next posts when scrolled down
*/ */
onScroll() { onScroll() {
this.feedService.getNextPosts(); this.feedService.getNextPosts();

@ -60,16 +60,19 @@ $mat-card-header-size: 40px !default
display: block display: block
margin-left: auto margin-left: auto
margin-right: auto margin-right: auto
margin-bottom: 0.5em
::ng-deep video ::ng-deep video
width: 100% width: 100%
max-height: 40vh max-height: 40vh
outline: none outline: none
user-select: none user-select: none
margin-bottom: 0.5em
::ng-deep audio ::ng-deep audio
width: 100% width: 100%
max-height: 40vh max-height: 40vh
outline: none outline: none
user-select: none user-select: none
margin-bottom: 0.5em
.mat-button .mat-button
min-width: 32px !important min-width: 32px !important

@ -54,7 +54,7 @@ $mat-card-header-size: 100px !default
#icon #icon
display: none display: none
position: absolute position: absolute
z-index: 11 z-index: 100
color: white color: white
$mat-card-header-size: 100px !default $mat-card-header-size: 100px !default

@ -17,7 +17,7 @@
</button> </button>
</mat-menu> </mat-menu>
</div> </div>
<div mat-card-avatar (click)="showGroupProfile(group)"> <div mat-card-avatar (click)="showFriendProfile(group)">
<img class="profile-picture" [src]="friend.profilePicture"/> <img class="profile-picture" [src]="friend.profilePicture"/>
</div> </div>
<mat-card-title (click)="showFriendProfile(friend)">{{friend.name}}</mat-card-title> <mat-card-title (click)="showFriendProfile(friend)">{{friend.name}}</mat-card-title>

@ -1,5 +1,6 @@
import {Author} from './author'; import {Author} from './author';
import {Activity} from './activity'; import {Activity} from './activity';
import { environment } from 'src/environments/environment';
export class Post { export class Post {
id: number; id: number;
@ -39,7 +40,7 @@ export class Post {
this.author = author; this.author = author;
this.activity = activity; this.activity = activity;
if (media) { if (media) {
this.mediaUrl = media.url; this.mediaUrl = environment.greenvironmentUrl + media.url;
this.mediaType = media.type; this.mediaType = media.type;
} }
} }

@ -10,8 +10,8 @@ import {BaseService} from '../base.service';
import {formatDate} from '@angular/common'; import {formatDate} from '@angular/common';
import {IFileUploadResult} from '../../models/interfaces/IFileUploadResult'; import {IFileUploadResult} from '../../models/interfaces/IFileUploadResult';
const createPostGqlQuery = `mutation($content: String!) { const createPostGqlQuery = `mutation($content: String!, $type: PostType) {
createPost(content: $content) { createPost(content: $content, type: $type) {
id, id,
content, content,
htmlContent, htmlContent,
@ -34,8 +34,8 @@ const createPostGqlQuery = `mutation($content: String!) {
createdAt} createdAt}
}`; }`;
const createPostActivityGqlQuery = `mutation($content: String!, $id: ID) { const createPostActivityGqlQuery = `mutation($content: String!, $id: ID, $type: PostType) {
createPost(content: $content activityId: $id) { createPost(content: $content activityId: $id, type: $type) {
id, id,
content, content,
htmlContent, 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) { getPosts (first: $first, offset: $offset, sort: $sort) {
id, id,
content, content,
@ -122,7 +122,7 @@ export class FeedService extends BaseService {
*/ */
private static buildGetPostBody(sort: string, offset: number, first: number = 10) { private static buildGetPostBody(sort: string, offset: number, first: number = 10) {
return { return {
query: getPostGqlQuery, variables: { query: getPostsGqlQuery, variables: {
first, first,
offset, offset,
sort sort
@ -145,10 +145,15 @@ export class FeedService extends BaseService {
* @param file * @param file
*/ */
public createPost(pContent: String, file?: File) { public createPost(pContent: String, file?: File) {
let type: string;
if (file) { type = 'MEDIA'; } else {
type = 'TEXT';
}
const body = { const body = {
query: createPostGqlQuery, query: createPostGqlQuery,
variables: { variables: {
content: pContent content: pContent,
type
} }
}; };
return this.createPostRequest(body, file); return this.createPostRequest(body, file);
@ -161,10 +166,15 @@ export class FeedService extends BaseService {
* @param file * @param file
*/ */
public createPostActivity(pContent: String, activityId: String, file?: File) { public createPostActivity(pContent: String, activityId: String, file?: File) {
let type: string;
if (file) { type = 'MEDIA'; } else {
type = 'TEXT';
}
const body = { const body = {
query: createPostActivityGqlQuery, variables: { query: createPostActivityGqlQuery, variables: {
content: pContent, content: pContent,
id: activityId id: activityId,
type
} }
}; };
return this.createPostRequest(body, file); return this.createPostRequest(body, file);
@ -176,27 +186,35 @@ export class FeedService extends BaseService {
* @param file - a file that is being uploaded with the post * @param file - a file that is being uploaded with the post
*/ */
private createPostRequest(body: { variables: any; query: string }, file?: File) { private createPostRequest(body: { variables: any; query: string }, file?: File) {
if (file) {
return this.postGraphql(body, null, 0) return this.postGraphql(body, null, 0)
.pipe(tap(response => { .pipe(tap(response => {
if (this.activePostList === Sort.NEW) {
const updatedPosts = this.posts.getValue(); const updatedPosts = this.posts.getValue();
if (this.activePostList === Sort.NEW) {
const post = this.constructPost(response); const post = this.constructPost(response);
updatedPosts.unshift(post);
if (file) {
this.uploadPostImage(post.id, file).subscribe((result) => { this.uploadPostImage(post.id, file).subscribe((result) => {
post.mediaUrl = result.fileName; post.mediaUrl = result.fileName;
post.mediaType = result.fileName.endsWith('.png') ? 'IMAGE' : 'VIDEO'; post.mediaType = result.fileName.endsWith('.png') ? 'IMAGE' : 'VIDEO';
updatedPosts.unshift(post);
this.posts.next(updatedPosts); this.posts.next(updatedPosts);
}, error => { }, error => {
console.error(error); console.error(error);
this.deletePost(post.id); this.deletePost(post.id);
}); });
} else {
this.posts.next(updatedPosts);
} }
}));
} else if (!file) {
return this.postGraphql(body, null, 0)
.pipe(tap(response => {
const updatedPosts = this.posts.getValue();
if (this.activePostList === Sort.NEW) {
const post = this.constructPost(response);
updatedPosts.unshift(post);
this.posts.next(updatedPosts);
} }
})); }));
} }
}
/** /**
* Uploads a file for a post * Uploads a file for a post

Loading…
Cancel
Save