diff --git a/angular.json b/angular.json index 5bf4787..7df165f 100644 --- a/angular.json +++ b/angular.json @@ -29,7 +29,8 @@ ], "styles": [ "src/styles/greenvironment-material-theme.scss", - "src/styles.sass" + "src/styles.sass", + "./node_modules/ngx-lightbox/lightbox.css" ], "scripts": [] }, diff --git a/ngsw-config.json b/ngsw-config.json index 4ddf1a7..4e9dd0a 100644 --- a/ngsw-config.json +++ b/ngsw-config.json @@ -21,6 +21,7 @@ "resources": { "files": [ "/assets/**", + "/data/**", "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)" ] } diff --git a/package-lock.json b/package-lock.json index e0e0d51..9a3fa2d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3136,9 +3136,9 @@ } }, "abbrev": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", - "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "accepts": { "version": "1.3.5", @@ -6931,9 +6931,9 @@ } }, "globule": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", - "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.0.tgz", + "integrity": "sha512-YlD4kdMqRCQHrhVdonet4TdRtv1/sZKepvoxNT4Nrhrp5HI8XFfc8kFlGlBn2myBo80aGp8Eft259mbcUJhgSg==", "requires": { "glob": "~7.1.1", "lodash": "~4.17.10", @@ -9104,6 +9104,11 @@ "opencollective-postinstall": "^2.0.2" } }, + "ngx-lightbox": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ngx-lightbox/-/ngx-lightbox-2.1.1.tgz", + "integrity": "sha512-mI1hUo/DrhcTeWi/7AVusKfzLr5ySz+EFrOksNlCEiaQKVMqCZdUgj+7ruKDROF7dZcNkJL9Wf99yyiG2nhezQ==" + }, "ngx-socket-io": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ngx-socket-io/-/ngx-socket-io-2.1.1.tgz", @@ -9223,9 +9228,9 @@ } }, "node-sass": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.0.tgz", - "integrity": "sha512-W1XBrvoJ1dy7VsvTAS5q1V45lREbTlZQqFbiHb3R3OTTCma0XBtuG6xZ6Z4506nR4lmHPTqVRwxT6KgtWC97CA==", + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.1.tgz", + "integrity": "sha512-TTWFx+ZhyDx1Biiez2nB0L3YrCZ/8oHagaDalbuBSlqXgUPsdkUSzJsVxeDO9LtPB49+Fh3WQl3slABo6AotNw==", "requires": { "async-foreach": "^0.1.3", "chalk": "^1.1.1", @@ -10944,9 +10949,9 @@ } }, "rxjs": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz", - "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==", + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", + "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", "requires": { "tslib": "^1.9.0" } diff --git a/package.json b/package.json index a12f028..4b76b7a 100644 --- a/package.json +++ b/package.json @@ -35,9 +35,10 @@ "hammerjs": "^2.0.8", "js-sha512": "^0.8.0", "ngx-infinite-scroll": "^8.0.1", + "ngx-lightbox": "^2.1.1", "ngx-socket-io": "^2.1.1", - "node-sass": "^4.13.0", - "rxjs": "~6.3.3", + "node-sass": "^4.13.1", + "rxjs": "~6.5.4", "ts-md5": "^1.2.7", "zone.js": "^0.8.29" }, diff --git a/src/app/app.component.sass b/src/app/app.component.sass index 663787d..e977ea0 100644 --- a/src/app/app.component.sass +++ b/src/app/app.component.sass @@ -11,10 +11,10 @@ $scrollbar-color-dark: transparent $scrollbar-thumb-color-dark: #aaa ::ng-deep body - scrollbar-color: $scrollbar-color $scrollbar-thumb-color + scrollbar-color: $scrollbar-thumb-color $scrollbar-color scrollbar-width: thin .dark-theme - scrollbar-color: $scrollbar-color-dark $scrollbar-thumb-color-dark + scrollbar-color: $scrollbar-thumb-color-dark $scrollbar-color-dark ::ng-deep ::-webkit-scrollbar width: 4px diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index 9da27bb..4a404b7 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -21,11 +21,4 @@ describe('AppComponent', () => { const app = fixture.debugElement.componentInstance; expect(app.title).toEqual('greenvironment'); }); - - it('should render title in a h1 tag', () => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1').textContent).toContain('Welcome to greenvironment!'); - }); }); diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 9877d08..68b4402 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -63,6 +63,7 @@ import {MatNativeDateModule, MatProgressBarModule} from '@angular/material/'; import {MatSnackBarModule} from '@angular/material/snack-bar'; import { ServiceWorkerModule } from '@angular/service-worker'; import { environment } from '../environments/environment'; +import {LightboxModule} from 'ngx-lightbox'; const config: SocketIoConfig = {url: 'http://localhost:4444', options: {}}; @@ -147,6 +148,7 @@ const appRoutes: Routes = [ MatDatepickerModule, MatSnackBarModule, MatProgressBarModule, + LightboxModule, ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }), ], entryComponents: [ diff --git a/src/app/components/feed/postlist/postlist.component.html b/src/app/components/feed/postlist/postlist.component.html index 4667aad..96e01cd 100644 --- a/src/app/components/feed/postlist/postlist.component.html +++ b/src/app/components/feed/postlist/postlist.component.html @@ -1,6 +1,6 @@ -
+
@@ -14,7 +14,7 @@
- {{post.author.name}} + {{post.author.name}} @{{post.author.handle}}

  {{post.date}}

@@ -25,17 +25,24 @@

- - {{post.upvotes}} - - {{post.downvotes}} -
+
+ + {{post.activity.points}} points earned through {{post.activity.name}} + +
+
+ +
{{post.upvotes}}
+ +
{{post.downvotes}}
+
+
{{post.activity.points}} points earned through {{post.activity.name}} diff --git a/src/app/components/feed/postlist/postlist.component.sass b/src/app/components/feed/postlist/postlist.component.sass index 9ace41a..ac7bf2d 100644 --- a/src/app/components/feed/postlist/postlist.component.sass +++ b/src/app/components/feed/postlist/postlist.component.sass @@ -17,7 +17,7 @@ $mat-card-header-size: 40px !default .mat-card-content overflow: auto - margin: 0 1em + margin: 0.5em 1em 0 ::ng-deep a color: $primary-color .mat-card-actions @@ -26,8 +26,14 @@ $mat-card-header-size: 40px !default ::ng-deep p margin: 0 - a:hover + .postlistUsername, a cursor: pointer + margin-right: 0.4em + &:hover + text-decoration: underline + + .postVoteButtons + display: inline-block #button-box text-align: right @@ -61,6 +67,7 @@ $mat-card-header-size: 40px !default border-radius: 50% width: $mat-card-header-size height: $mat-card-header-size + cursor: pointer .activity-info display: contents @@ -74,4 +81,28 @@ $mat-card-header-size: 40px !default &.voted scale: 0.9 + .voteCount + display: inline + + @media (max-width: 959px) + .activity-info > .span + margin-left: 1em + width: calc(100% - 1em) + display: block + text-align: left + .postVoteButtons + text-align: end + margin-right: 0.5em + display: flex + align-items: center + .voteButton + scale: 1 + &.voted + scale: 1.1 + + .mat-card-actions + display: flex + justify-content: end + align-items: center + diff --git a/src/app/components/profile/profile.component.html b/src/app/components/profile/profile.component.html index 7d3b3d0..e427abc 100644 --- a/src/app/components/profile/profile.component.html +++ b/src/app/components/profile/profile.component.html @@ -3,11 +3,11 @@ -
+
camera_alt
-
+
@@ -44,12 +44,12 @@ -
+
camera_alt
-
- +
+
{{userProfile.username}} @{{userProfile.handle}} diff --git a/src/app/components/profile/profile.component.sass b/src/app/components/profile/profile.component.sass index 81986bd..3857047 100644 --- a/src/app/components/profile/profile.component.sass +++ b/src/app/components/profile/profile.component.sass @@ -54,8 +54,11 @@ color: white $mat-card-header-size: 100px !default -.hover-box + +.profile-picture-container cursor: pointer + z-index: 11 +.hover-box text-align: center display: flex justify-content: center diff --git a/src/app/components/profile/profile.component.ts b/src/app/components/profile/profile.component.ts index 9f92026..815ba80 100644 --- a/src/app/components/profile/profile.component.ts +++ b/src/app/components/profile/profile.component.ts @@ -9,6 +9,7 @@ import {HttpClient} from '@angular/common/http'; import {SelfService} from '../../services/selfservice/self.service'; import {MatDialog} from '@angular/material'; import {DialogFileUploadComponent} from './fileUpload/fileUpload.component'; +import {Lightbox} from 'ngx-lightbox'; @Component({ selector: 'app-profile', @@ -32,7 +33,7 @@ export class ProfileComponent implements OnInit { private requestService: RequestService, private data: DatasharingService, private profileService: ProfileService, - private selfService: SelfService, + private lightbox: Lightbox, public dialog: MatDialog) { router.events.forEach((event) => { // check if the user is on the profile page (of userY) and routes to the page of userY (e.g. his own page) @@ -85,4 +86,15 @@ export class ProfileComponent implements OnInit { } }); } + + /** + * Opens a lightbox with the users profile picture + */ + openPfpLightbox() { + this.lightbox.open([{ + src: this.userProfile.profilePicture, + caption: `${this.userProfile.username}'s profile picture`, + thumb: this.userProfile.profilePicture, + }], 0, {disableScrolling: true}); + } } diff --git a/src/app/services/feed/feed.service.ts b/src/app/services/feed/feed.service.ts index 0a83b24..62aea92 100644 --- a/src/app/services/feed/feed.service.ts +++ b/src/app/services/feed/feed.service.ts @@ -7,6 +7,7 @@ import {Activity} from 'src/app/models/activity'; import {BehaviorSubject} from 'rxjs'; import {tap} from 'rxjs/operators'; import {BaseService} from '../base.service'; +import {formatDate} from '@angular/common'; const createPostGqlQuery = `mutation($content: String!) { createPost(content: $content) { @@ -125,6 +126,15 @@ export class FeedService extends BaseService { }; } + /** + * Returns if the input date is today + * @param date + */ + private static dateIsToday(date: Date) { + date = new Date(date); + return new Date().setHours(0, 0, 0, 0) === date.setHours(0, 0, 0, 0); + } + /** * Creates a new post * @param pContent @@ -240,8 +250,13 @@ export class FeedService extends BaseService { .pipe(this.retryRated()) .subscribe(response => { const posts = this.constructAllPosts(response); - const updatedPostList = this.posts.getValue().concat(posts); - this.posts.next(updatedPostList); + const previousPosts = this.posts.getValue(); + for (const post of previousPosts.reverse()) { + if (!posts.find(p => p.id === post.id)) { + posts.unshift(post); + } + } + this.posts.next(posts); if (posts.length < this.offsetStep) { this.postsAvailable.next(false); } @@ -257,8 +272,13 @@ export class FeedService extends BaseService { profilePicture = 'assets/images/default-profilepic.svg'; } const author = new Author(post.author.id, post.author.name, post.author.handle, profilePicture); - const temp = new Date(Number(post.createdAt)); - const date = temp.toLocaleString('en-GB'); + const postDate = new Date(Number(post.createdAt)); + let date: string; + if (FeedService.dateIsToday(postDate)) { + date = formatDate(postDate, 'HH:mm', 'en-GB'); + } else { + date = formatDate(postDate, 'dd.MM.yy HH:mm', 'en-GB'); + } let activity: Activity; if (post.activity) { activity = new Activity( @@ -293,8 +313,13 @@ export class FeedService extends BaseService { profilePicture = 'assets/images/default-profilepic.svg'; } const author = new Author(post.author.id, post.author.name, post.author.handle, profilePicture); - const temp = new Date(Number(post.createdAt)); - const date = temp.toLocaleString('en-GB'); + const postDate = new Date(Number(post.createdAt)); + let date: string; + if (FeedService.dateIsToday(postDate)) { + date = formatDate(postDate, 'HH:mm', 'en-GB'); + } else { + date = formatDate(postDate, 'dd.MM.yy HH:mm', 'en-GB'); + } let activity: Activity; if (post.activity) { activity = new Activity(