diff --git a/.angular-cli.json b/.angular-cli.json --- a/.angular-cli.json +++ b/.angular-cli.json @@ -24,7 +24,9 @@ "../node_modules/font-awesome/css/font-awesome.css", "theme.scss" ], - "scripts": [], + "scripts": [ + "../node_modules/compressorjs/dist/compressor.min.js" + ], "environmentSource": "environments/environment.ts", "environments": { "dev": "environments/environment.ts", diff --git a/package-lock.json b/package-lock.json --- a/package-lock.json +++ b/package-lock.json @@ -472,6 +472,14 @@ "tslib": "^1.7.1" } }, + "@angular/flex-layout": { + "version": "5.0.0-beta.15", + "resolved": "https://registry.npmjs.org/@angular/flex-layout/-/flex-layout-5.0.0-beta.15.tgz", + "integrity": "sha512-rGvvjDu0PMrsfTsNX+qcNc4EloKGXTxW8FT1tKcdIxOUMRQkvflkwAnKW2kRWNfEgDtBNt+VNP98u2w+athvZQ==", + "requires": { + "tslib": "^1.7.1" + } + }, "@angular/forms": { "version": "5.2.11", "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-5.2.11.tgz", @@ -1511,6 +1519,11 @@ "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", "dev": true }, + "blueimp-canvas-to-blob": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/blueimp-canvas-to-blob/-/blueimp-canvas-to-blob-3.14.0.tgz", + "integrity": "sha512-i6I2CiX1VR8YwUNYBo+dM8tg89ns4TTHxSpWjaDeHKcYS3yFalpLCwDaY21/EsJMufLy2tnG4j0JN5L8OVNkKQ==" + }, "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", @@ -2260,6 +2273,15 @@ } } }, + "compressorjs": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/compressorjs/-/compressorjs-1.0.5.tgz", + "integrity": "sha512-QUcAxEOG/qc/BoSbmv9Y1lZrKz7uEPbMirNgT4c/S0xibRB24hz+2pkNBUs9FPvY5nKKxsELkXIono/DBwe8XQ==", + "requires": { + "blueimp-canvas-to-blob": "^3.14.0", + "is-blob": "^2.0.1" + } + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -5592,6 +5614,11 @@ "binary-extensions": "^1.0.0" } }, + "is-blob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-blob/-/is-blob-2.0.1.tgz", + "integrity": "sha512-SmqVJYMnAeqrKLcwq6TXu1rpAg3yipVlMZIqR5u510rxoOzJGW9GQY6g+WtWkcc44pjbWAuxzZDCkbgf5e6r0Q==" + }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", @@ -7772,6 +7799,14 @@ "ngx-window-token": "0.0.4" } }, + "ngx-image-compress": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/ngx-image-compress/-/ngx-image-compress-7.2.4.tgz", + "integrity": "sha512-FKff6F4y3kj6xX/zrPCoti02jALiejH2oaTOywML7QQL0ontIPytss6NNCDkDBN9YILt1g/KKn3kR3R3utcB1A==", + "requires": { + "tslib": "^1.9.0" + } + }, "ngx-img-cropper": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/ngx-img-cropper/-/ngx-img-cropper-0.11.0.tgz", diff --git a/package.json b/package.json --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "start": "ng serve", "build": "ng build", "test": "ng test", - "lint": "ng lint", + "lint": "tslint --project tslint.json --fix", "e2e": "ng e2e", "precache": "sw-precache --verbose --config=sw-precache-config.js" }, @@ -18,6 +18,7 @@ "@angular/common": "^5.2.11", "@angular/compiler": "^5.2.11", "@angular/core": "^5.2.11", + "@angular/flex-layout": "^5.0.0-beta.15", "@angular/forms": "^5.2.11", "@angular/http": "^5.2.11", "@angular/material": "^5.2.5", @@ -30,6 +31,7 @@ "angular2-masonry": "^0.4.0", "angular2-recaptcha": "^0.6.0", "angulartics2": "^2.4.0", + "compressorjs": "^1.0.5", "core-js": "^2.5.1", "font-awesome": "^4.7.0", "hammerjs": "^2.0.8", @@ -37,6 +39,7 @@ "markdown-it-regex": "^0.2.0", "material-design-icons": "^3.0.1", "ngx-clipboard": "^10.0.0", + "ngx-image-compress": "^7.2.4", "ngx-img-cropper": "^0.11.0", "ngx-pagination": "^3.0.3", "rxjs": "^5.5.11", diff --git a/src/app/404component/404.component.html b/src/app/404component/404.component.html --- a/src/app/404component/404.component.html +++ b/src/app/404component/404.component.html @@ -1,4 +1,4 @@ - +WildFyre

404?
diff --git a/src/app/_dialogs/avatar.dialog.component.ts b/src/app/_dialogs/avatar.dialog.component.ts deleted file mode 100644 --- a/src/app/_dialogs/avatar.dialog.component.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { Component, ViewChild } from '@angular/core'; -import { MatDialogRef, MatSnackBar } from '@angular/material'; -import { Author } from '../_models/author'; -import { ImageCropperComponent, CropperSettings, Bounds } from 'ngx-img-cropper'; - -@Component({ - template: ` -

Change Avatar

- - - - - - -
- - -
- ` -}) -export class AvatarDialogComponent { - @ViewChild('cropper', undefined) cropper: ImageCropperComponent; - author: Author; - croppedHeight: number; - croppedWidth: number; - cropperSettings: CropperSettings; - data: any; - model: any = {}; - profilePicture: any; - - constructor( - public dialogRef: MatDialogRef, - public snackBar: MatSnackBar - ) { - this.cropperSettings = new CropperSettings(); - this.cropperSettings.width = 200; - this.cropperSettings.height = 200; - - this.cropperSettings.croppedWidth = 200; - this.cropperSettings.croppedHeight = 200; - - this.cropperSettings.canvasWidth = 200; - this.cropperSettings.canvasHeight = 200; - - this.cropperSettings.minWidth = 10; - this.cropperSettings.minHeight = 10; - - this.cropperSettings.rounded = false; - this.cropperSettings.keepAspect = true; - - this.cropperSettings.cropperDrawSettings.strokeColor = 'rgb(191, 63, 127)'; - this.cropperSettings.cropperDrawSettings.strokeWidth = 3; - - this.data = {}; - } - - cropped(bounds: Bounds) { - this.croppedHeight = bounds.bottom - bounds.top; - this.croppedWidth = bounds.right - bounds.left; - if (this.data) { - // convert the data URL to a byte string - const byteString = atob(this.data.image.split(',')[1]); - - // pull out the mime type from the data URL - const mimeString = this.data.image.split(',')[0].split(':')[1].split(';')[0]; - - // Convert to byte array - const ab = new ArrayBuffer(byteString.length); - const ia = new Uint8Array(ab); - for (let i = 0; i < byteString.length; i++) { - ia[i] = byteString.charCodeAt(i); - } - - // Create a blob that looks like a file. - this.profilePicture = new Blob([ab], {'type': mimeString }); - this.profilePicture['name'] = this.author.name; - switch (this.profilePicture.type) { - case 'image/jpeg': - this.profilePicture['name'] += '.jpg'; - break; - case 'image/png': - this.profilePicture['name'] += '.png'; - break; - } - } else { - const snackBarRef = this.snackBar.open('You did not select a valid image file', 'Close', { - duration: 3000 - }); - } - } - - returnInformation(bool: boolean) { - const message = { - 'profilePicture': this.profilePicture, - 'bool': bool - }; - - this.dialogRef.close(message); - } -} diff --git a/src/app/_dialogs/bio.dialog.component.ts b/src/app/_dialogs/bio.dialog.component.ts deleted file mode 100644 --- a/src/app/_dialogs/bio.dialog.component.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Component } from '@angular/core'; -import { MatDialogRef } from '@angular/material'; - -@Component({ - template: ` -

Change Bio

- - - -
- - -
- ` -}) -export class BioDialogComponent { - model: any = {}; - - constructor( - public dialogRef: MatDialogRef - ) { } - - returnInformation(bool: boolean) { - const message = { - 'bio': this.model.bio, - 'bool': bool - }; - - this.dialogRef.close(message); - } -} diff --git a/src/app/_dialogs/email.dialog.component.ts b/src/app/_dialogs/email.dialog.component.ts deleted file mode 100644 --- a/src/app/_dialogs/email.dialog.component.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Component } from '@angular/core'; -import { MatDialogRef } from '@angular/material'; - -@Component({ - template: ` -

Change Email

- - - -
- - -
- ` -}) -export class EmailDialogComponent { - model: any = {}; - - constructor( - public dialogRef: MatDialogRef - ) { } - - returnInformation(bool: boolean) { - const message = { - 'email': this.model.email, - 'bool': bool - }; - - this.dialogRef.close(message); - } -} diff --git a/src/app/_dialogs/password.dialog.component.ts b/src/app/_dialogs/password.dialog.component.ts deleted file mode 100644 --- a/src/app/_dialogs/password.dialog.component.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { Component, OnDestroy } from '@angular/core'; -import { MatDialogRef, MatSnackBar } from '@angular/material'; -import { Subject } from 'rxjs/Subject'; -import { Account } from '../_models/account'; -import { Author } from '../_models/author'; -import { PasswordError } from '../_models/password'; -import { AuthenticationService } from '../_services/authentication.service'; -import { ProfileService } from '../_services/profile.service'; - -@Component({ - template: ` -

Change Password

-
- Passwords must contain at least 8 characters and be alphanumeric (At least 1 letter and 1 number) -
-
-
    -
  • {{err}}
  • -
-
-
-
-
    -
  • {{err}}
  • -
-
- - - -
- - - -
Password is required
-
-
    -
  • {{err}}
  • -
-
-
- -
- - - -
Password is required
-
-
    -
  • {{err}}
  • -
-
-
- -
- - - -
Password is required
-
-
    -
  • {{err}}
  • -
-
-
-
-
- - -
- ` -}) -export class PasswordDialogComponent implements OnDestroy { - account: Account; - author: Author; - componentDestroyed: Subject = new Subject(); - errors: PasswordError; - model: any = {}; - - constructor( - public dialogRef: MatDialogRef, - public snackBar: MatSnackBar, - private authenticationService: AuthenticationService, - private profileService: ProfileService, - ) { } - - ngOnDestroy() { - this.componentDestroyed.next(true); - this.componentDestroyed.complete(); - } - - submitEditPassword() { - this.authenticationService.login(this.account.username, this.model.oldPassword) - .takeUntil(this.componentDestroyed) - .subscribe(result => { - if (!result.getError()) { - if (this.model.newPassword1 === this.model.newPassword2) { - this.profileService.setPassword(this.model.newPassword1) - .takeUntil(this.componentDestroyed) - .subscribe(result2 => { - if (!result2.getError()) { - this.authenticationService.login(this.account.username, this.model.newPassword1) - .takeUntil(this.componentDestroyed) - .subscribe(result3 => { - if (!result3.getError()) { - this.model.oldPassword = ''; - this.model.newPassword1 = ''; - this.model.newPassword2 = ''; - this.returnInformation(true); - } else { - this.snackBar.open('Error could not set token', 'Close'); - } - }); - } else { - this.errors = result2.getError(); - this.snackBar.open('You did not follow the requirements', 'Close'); - } - }); - - } else { - this.errors = result.getError(); - this.snackBar.open('Your new passwords do not match', 'Close'); - } - } else { - this.errors = result.getError(); - this.snackBar.open('This is not your current password', 'Close'); - } - }); - } - - returnInformation(bool: boolean) { - const message = { - 'bool': bool - }; - - this.dialogRef.close(message); - } -} diff --git a/src/app/_models/account.ts b/src/app/_models/account.ts --- a/src/app/_models/account.ts +++ b/src/app/_models/account.ts @@ -21,7 +21,7 @@ export class AccountError extends Account { constructor( public non_field_errors?: string[], - public _text?: string[] + public text?: string[] ) { super(null, null, null); } diff --git a/src/app/_models/auth.ts b/src/app/_models/auth.ts --- a/src/app/_models/auth.ts +++ b/src/app/_models/auth.ts @@ -11,8 +11,8 @@ export class AuthError extends Auth { constructor( public non_field_errors?: string[], - public _username?: string[], - public _password?: string[] + public username?: string[], + public password?: string[] ) { super(); } getError(): AuthError { diff --git a/src/app/_models/author.ts b/src/app/_models/author.ts --- a/src/app/_models/author.ts +++ b/src/app/_models/author.ts @@ -25,7 +25,7 @@ export class AuthorError extends Author { constructor( public non_field_errors?: string[], - public _text?: string[] + public text?: string[] ) { super(null, null, null, null, null); } diff --git a/src/app/_models/ban.ts b/src/app/_models/ban.ts --- a/src/app/_models/ban.ts +++ b/src/app/_models/ban.ts @@ -39,7 +39,7 @@ export class BanError extends Ban { constructor( public non_field_errors?: string[], - public _text?: string[] + public text?: string[] ) { super(null, null, null, null, null, null, null, null, null); } diff --git a/src/app/_models/choice.ts b/src/app/_models/choice.ts --- a/src/app/_models/choice.ts +++ b/src/app/_models/choice.ts @@ -19,7 +19,7 @@ export class ChoiceError extends Choice { constructor( public non_field_errors?: string[], - public _text?: string[] + public text?: string[] ) { super(null, null); } diff --git a/src/app/_models/comment.ts b/src/app/_models/comment.ts --- a/src/app/_models/comment.ts +++ b/src/app/_models/comment.ts @@ -1,8 +1,6 @@ import {Author} from './author'; export class Comment { - public created: Date; - static parse(obj: any) { return new Comment( obj.id, @@ -16,11 +14,13 @@ constructor( public id: number, public author: Author, - created: string, + public created: string, public text: string, public image: string ) { - this.created = new Date(created); + const options = { year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit' }; + const time = new Date(created); + this.created = time.toLocaleDateString(undefined, options); } getError(): CommentError { diff --git a/src/app/_models/image.ts b/src/app/_models/image.ts --- a/src/app/_models/image.ts +++ b/src/app/_models/image.ts @@ -21,7 +21,7 @@ export class ImageError extends Image { constructor( public non_field_errors?: string[], - public _text?: string[] + public text?: string[] ) { super(null, null, null); } diff --git a/src/app/_models/password.ts b/src/app/_models/password.ts --- a/src/app/_models/password.ts +++ b/src/app/_models/password.ts @@ -11,10 +11,10 @@ export class PasswordError extends Password { constructor( public non_field_errors?: string[], - public _text?: string[], - public _oldPassword?: string[], - public _newPassword1?: string[], - public _newPassword2?: string[] + public text?: string[], + public oldPassword?: string[], + public newPassword1?: string[], + public newPassword2?: string[] ) { super(); } getError(): PasswordError { diff --git a/src/app/_models/post.ts b/src/app/_models/post.ts --- a/src/app/_models/post.ts +++ b/src/app/_models/post.ts @@ -3,8 +3,6 @@ import { Image } from './image'; export class Post { - public created: Date; - static parse(obj: any) { return new Post( obj.id, @@ -47,14 +45,16 @@ public author: Author, public anonym: boolean, public subscribed: boolean, - created: string, + public created: string, public active: boolean, public text: string, public image: string, public additional_images: Image[], public comments: Comment[] ) { - this.created = new Date(created); + const options = { year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit' }; + const time = new Date(created); + this.created = time.toLocaleDateString(undefined, options); } getError(): PostError { diff --git a/src/app/_models/profile.ts b/src/app/_models/profile.ts --- a/src/app/_models/profile.ts +++ b/src/app/_models/profile.ts @@ -25,7 +25,7 @@ export class ProfileError extends Profile { constructor( public non_field_errors?: string[], - public _text?: string[] + public text?: string[] ) { super(null, null, null, null, null); } diff --git a/src/app/_models/superBan.ts b/src/app/_models/superBan.ts --- a/src/app/_models/superBan.ts +++ b/src/app/_models/superBan.ts @@ -31,7 +31,7 @@ export class SuperBanError extends SuperBan { constructor( public non_field_errors?: string[], - public _text?: string[] + public text?: string[] ) { super(null, null, null, null); } diff --git a/src/app/_models/superNotification.ts b/src/app/_models/superNotification.ts --- a/src/app/_models/superNotification.ts +++ b/src/app/_models/superNotification.ts @@ -31,7 +31,7 @@ export class SuperNotificationError extends SuperNotification { constructor( public non_field_errors?: string[], - public _text?: string[] + public text?: string[] ) { super(null, null, null, null); } diff --git a/src/app/_models/superPost.ts b/src/app/_models/superPost.ts --- a/src/app/_models/superPost.ts +++ b/src/app/_models/superPost.ts @@ -22,10 +22,9 @@ public previous: string, public results: Post[] ) { - // Sort posts results.sort((a: Post, b: Post) => { - return b.created.getTime() - a.created.getTime(); + return new Date(b.created).getTime() - new Date(a.created).getTime(); }); } @@ -37,7 +36,7 @@ export class SuperPostError extends SuperPost { constructor( public non_field_errors?: string[], - public _text?: string[] + public text?: string[] ) { super(null, null, null, null); } diff --git a/src/app/_modules/ng2share/platforms.utils.ts b/src/app/_modules/ng2share/platforms.utils.ts --- a/src/app/_modules/ng2share/platforms.utils.ts +++ b/src/app/_modules/ng2share/platforms.utils.ts @@ -104,4 +104,4 @@ logo: 'mail', text: 'Mail', } -} +}; diff --git a/src/app/_modules/ngx-masonry/ngx-masonry-options.interface.ts b/src/app/_modules/ngx-masonry/ngx-masonry-options.interface.ts deleted file mode 100644 --- a/src/app/_modules/ngx-masonry/ngx-masonry-options.interface.ts +++ /dev/null @@ -1,15 +0,0 @@ -export interface NgxMasonryOptions { - itemSelector?: string; - columnWidth?: number | string; - gutter?: number | string; - percentPosition?: boolean; - stamp?: string; - fitWidth?: boolean; - originLeft?: boolean; - originTop?: boolean; - containerStyle?: string; - transitionDuration?: string; - resize?: boolean; - initLayout?: boolean; - horizontalOrder?: boolean; -} diff --git a/src/app/_modules/ngx-masonry/ngx-masonry.component.ts b/src/app/_modules/ngx-masonry/ngx-masonry.component.ts deleted file mode 100644 --- a/src/app/_modules/ngx-masonry/ngx-masonry.component.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { Component, OnInit, OnChanges, SimpleChanges, OnDestroy, - Input, Output, ElementRef, EventEmitter, PLATFORM_ID, Inject } from '@angular/core'; -import { isPlatformBrowser } from '@angular/common'; - -declare var require: any; -const imagesLoaded: any = undefined; -let masonryConstructor: any = undefined; - -import { NgxMasonryOptions } from './ngx-masonry-options.interface'; - -@Component({ - selector: '[ngx-masonry], ngx-masonry', - template: '', - styles: [ - ` - :host { - display: block; - } - ` - ] -}) -export class NgxMasonryComponent implements OnInit, OnChanges, OnDestroy { - public _msnry: any; - - // Inputs - @Input() public options: NgxMasonryOptions; - @Input() public useImagesLoaded: Boolean = false; - @Input() updateLayout: Boolean = false; - - // Outputs - @Output() layoutComplete: EventEmitter = new EventEmitter(); - @Output() removeComplete: EventEmitter = new EventEmitter(); - - constructor(@Inject(PLATFORM_ID) private platformId: any, private _element: ElementRef) {} - - ngOnInit() { - ///TODO: How to load imagesloaded only if this.useImagesLoaded===true? - if (this.useImagesLoaded && imagesLoaded === undefined) { - // imagesLoaded = require('imagesloaded'); - } - - if (isPlatformBrowser(this.platformId) && masonryConstructor === undefined) { - masonryConstructor = require('masonry-layout'); - } - - // Create masonry options object - if (!this.options) { - this.options = {}; - } - - // Set default itemSelector - if (!this.options.itemSelector) { - this.options.itemSelector = '[ngx-masonry-item], ngx-masonry-item'; - } - - if (isPlatformBrowser(this.platformId)) { - // Initialize Masonry - this._msnry = new masonryConstructor(this._element.nativeElement, this.options); - - // Bind to events - this._msnry.on('layoutComplete', (items: any) => { - this.layoutComplete.emit(items); - }); - this._msnry.on('removeComplete', (items: any) => { - this.removeComplete.emit(items); - }); - } - } - - ngOnChanges(changes: SimpleChanges) { - // only update layout if it's not the first change - if (changes.updateLayout) { - if (!changes.updateLayout.firstChange) { - this.layout(); - } - } - } - - ngOnDestroy() { - if (this._msnry) { - this._msnry.destroy(); - } - } - - public layout() { - setTimeout(() => { - this._msnry.layout(); - }); - } - - public reloadItems() { - setTimeout(() => { - this._msnry.reloadItems(); - }); - } - - // public add(element: HTMLElement, prepend: boolean = false) { - public add(element: HTMLElement) { - let isFirstItem = false; - - // Check if first item - if (this._msnry.items.length === 0) { - isFirstItem = true; - } - - if (this.useImagesLoaded) { - imagesLoaded(element, (instance: any) => { - this._element.nativeElement.appendChild(element); - - // Tell Masonry that a child element has been added - this._msnry.appended(element); - - // layout if first item - if (isFirstItem) { - this.layout(); - } - }); - - this._element.nativeElement.removeChild(element); - } else { - // Tell Masonry that a child element has been added - this._msnry.appended(element); - - // layout if first item - if (isFirstItem) { - this.layout(); - } - } - } - - public remove(element: HTMLElement) { - // Tell Masonry that a child element has been removed - this._msnry.remove(element); - - // Layout items - this.layout(); - } -} diff --git a/src/app/_modules/ngx-masonry/ngx-masonry.directive.ts b/src/app/_modules/ngx-masonry/ngx-masonry.directive.ts deleted file mode 100644 --- a/src/app/_modules/ngx-masonry/ngx-masonry.directive.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { Directive, Inject, ElementRef, forwardRef, OnDestroy, AfterViewInit, PLATFORM_ID } from '@angular/core'; - -import { NgxMasonryComponent } from './ngx-masonry.component'; -import { isPlatformBrowser } from '@angular/common'; - -interface MutationWindow extends Window { - MutationObserver: any; - WebKitMutationObserver: any; -} - -declare var window: MutationWindow; - -@Directive({ - selector: '[ngx-masonry-item], ngx-masonry-item' -}) -export class NgxMasonryDirective implements OnDestroy, AfterViewInit { - constructor( - private _element: ElementRef, - @Inject(forwardRef(() => NgxMasonryComponent)) - private _parent: NgxMasonryComponent, - @Inject(PLATFORM_ID) private platformId: any - ) {} - - ngAfterViewInit() { - if (isPlatformBrowser(this.platformId)) { - this._parent.add(this._element.nativeElement); - this.watchForHtmlChanges(); - } - } - - ngOnDestroy() { - if (isPlatformBrowser(this.platformId)) { - this._parent.remove(this._element.nativeElement); - } - } - - /** When HTML in brick changes dinamically, observe that and change layout */ - private watchForHtmlChanges(): void { - MutationObserver = window.MutationObserver || window.WebKitMutationObserver; - - if (MutationObserver) { - /** Watch for any changes to subtree */ - const self = this; - const observer = new MutationObserver(function(mutations: any, observerFromElement: any) { - self._parent.layout(); - }); - - // define what element should be observed by the observer - // and what types of mutations trigger the callback - observer.observe(this._element.nativeElement, { - subtree: true, - childList: true - }); - } - } -} diff --git a/src/app/_modules/ngx-masonry/ngx-masonry.module.ts b/src/app/_modules/ngx-masonry/ngx-masonry.module.ts deleted file mode 100644 --- a/src/app/_modules/ngx-masonry/ngx-masonry.module.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; - -/*-- ngx-masonry --*/ -import { NgxMasonryComponent } from './ngx-masonry.component'; -import { NgxMasonryDirective } from './ngx-masonry.directive'; - -@NgModule({ - imports: [ - CommonModule - ], - exports: [ - NgxMasonryComponent, - NgxMasonryDirective - ], - declarations: [ - NgxMasonryComponent, - NgxMasonryDirective - ] -}) -export class NgxMasonryModule {} diff --git a/src/app/_pipes/marked.pipe.ts b/src/app/_pipes/marked.pipe.ts --- a/src/app/_pipes/marked.pipe.ts +++ b/src/app/_pipes/marked.pipe.ts @@ -1,7 +1,7 @@ import { Pipe, PipeTransform } from '@angular/core'; import { Comment } from '../_models/comment'; import { Post } from '../_models/post'; -import * as C from '../_models/constants' +import * as C from '../_models/constants'; import * as marked from 'markdown-it'; import markdownItRegex from 'markdown-it-regex'; diff --git a/src/app/_services/area.service.ts b/src/app/_services/area.service.ts --- a/src/app/_services/area.service.ts +++ b/src/app/_services/area.service.ts @@ -17,6 +17,7 @@ ) { } getAreaRep(area: string): Observable { + // Get area rep from api, cache response if (this.reputation[area]) { return Observable.of(this.reputation[area]); } else { @@ -29,18 +30,17 @@ } getAreas(): Observable { - // get areas from api + // Get areas from api, cache response if (!this.areas) { - return this.httpService.GET('/areas/') - .map(response => { - const areas: Area[] = []; - for (let i = 0; i < response.length; i++) { - areas.push(Area.parse(response[i])) - } - this.areas = areas; - this.currentAreaName = this.areas[0].name; - return areas; - }); + return this.httpService.GET('/areas/') + .map(response => { + const areas: Area[] = []; + for (let i = 0; i < response.length; i++) { + areas.push(Area.parse(response[i])); + } + this.areas = areas; + return areas; + }); } else { return Observable.of(this.areas); } diff --git a/src/app/_services/authentication.service.ts b/src/app/_services/authentication.service.ts --- a/src/app/_services/authentication.service.ts +++ b/src/app/_services/authentication.service.ts @@ -35,12 +35,11 @@ return Auth.parse(response); }) .catch((error) => { - const body = JSON.parse(error._body); return Observable.of( new AuthError( - body.non_field_errors || null, - body.username || null, - body.password || null + error.error.non_field_errors, + error.error.username, + error.error.password, ) ); }); diff --git a/src/app/_services/http.service.ts b/src/app/_services/http.service.ts --- a/src/app/_services/http.service.ts +++ b/src/app/_services/http.service.ts @@ -78,6 +78,8 @@ // Handling methods private handleError(error: any): Observable { + console.error(error); + let message: string; let action = 'Close'; let onAction: Function; diff --git a/src/app/_services/post.service.ts b/src/app/_services/post.service.ts --- a/src/app/_services/post.service.ts +++ b/src/app/_services/post.service.ts @@ -57,10 +57,10 @@ this.navBarService.clearInputs.next(true); return comment; }) - .catch((err) => { + .catch((error) => { return Observable.of(new CommentError( - JSON.parse(err._body).non_field_errors, - JSON.parse(err._body).text + error.error.non_field_errors, + error.error.text )); }); } @@ -92,8 +92,8 @@ }) .catch((error) => { return Observable.of(new PostError( - JSON.parse(error._body).non_field_errors, - JSON.parse(error._body)._text + error.error.non_field_errors, + error.error._text )); }); } else if (draft && postID === null) { @@ -103,8 +103,8 @@ }) .catch((error) => { return Observable.of(new PostError( - JSON.parse(error._body).non_field_errors, - JSON.parse(error._body)._text + error.error.non_field_errors, + error.error._text )); }); } else if (draft && postID !== null) { @@ -114,8 +114,8 @@ }) .catch((error) => { return Observable.of(new PostError( - JSON.parse(error._body).non_field_errors, - JSON.parse(error._body)._text + error.error.non_field_errors, + error.error._text )); }); } else { diff --git a/src/app/_services/profile.service.ts b/src/app/_services/profile.service.ts --- a/src/app/_services/profile.service.ts +++ b/src/app/_services/profile.service.ts @@ -74,10 +74,10 @@ console.log('You leveled up some stats'); return Author.parse(response); - }).catch((err) => { + }).catch((error) => { return Observable.of(new AuthorError( - JSON.parse(err._body).non_field_errors, - JSON.parse(err._body).text + error.error.non_field_errors, + error.error.text )); }); } @@ -92,10 +92,10 @@ console.log('You have mail!'); return Account.parse(response); - }).catch((err) => { + }).catch((error) => { return Observable.of(new AccountError( - JSON.parse(err._body).non_field_errors, - JSON.parse(err._body).text + error.error.non_field_errors, + error.error.text )); }); } @@ -110,26 +110,26 @@ console.log('You have been securely encryptified'); return Account.parse(response); - }).catch((err) => { + }).catch((error) => { return Observable.of(new AccountError( - JSON.parse(err._body).non_field_errors, - JSON.parse(err._body).text + error.error.non_field_errors, + error.error.text )); }); } setProfilePicture(image: any): Observable { - const formData: FormData = new FormData(); - formData.append('avatar', image, image.name); + const formData: FormData = new FormData(); + formData.append('avatar', image, image.name); return this.httpService.PUT_IMAGE('/users/', formData) .map((response: Response) => { console.log('You looked in the mirror and got frightened'); return Profile.parse(response); - }).catch((err) => { + }).catch((error) => { return Observable.of(new ProfileError( - JSON.parse(err._body).non_field_errors, - JSON.parse(err._body).text + error.error.non_field_errors, + error.error.text )); }); } diff --git a/src/app/_services/reason.service.ts b/src/app/_services/reason.service.ts --- a/src/app/_services/reason.service.ts +++ b/src/app/_services/reason.service.ts @@ -17,7 +17,7 @@ .map(response => { const choices: Choice[] = []; for (let i = 0; i < response.length; i++) { - choices.push(Choice.parse(response[i])) + choices.push(Choice.parse(response[i])); } return choices; }); diff --git a/src/app/_services/registration.service.spec.ts b/src/app/_services/registration.service.spec.ts --- a/src/app/_services/registration.service.spec.ts +++ b/src/app/_services/registration.service.spec.ts @@ -9,25 +9,25 @@ describe('RegistrationService', () => { const recoverTransaction = { - non_field_errors: "Error", - username: "Test", - email: "test@test.com", - captcha: "jhsadbgfajh2234", + non_field_errors: 'Error', + username: 'Test', + email: 'test@test.com', + captcha: 'jhsadbgfajh2234', }; const reset = { - non_field_errors: "Error", - new_password: "password123", - token: "dfgsdfgwqe45t", - transaction: "3456345-34534-43534", - captcha: "jhsadbgfajh2234", + non_field_errors: 'Error', + new_password: 'password123', + token: 'dfgsdfgwqe45t', + transaction: '3456345-34534-43534', + captcha: 'jhsadbgfajh2234', }; const registration = { - non_field_errors: "Error", - username: "user123", - email: "test@test.com", - password: "password123", - captcha: "jhsadbgfajh2234", + non_field_errors: 'Error', + username: 'user123', + email: 'test@test.com', + password: 'password123', + captcha: 'jhsadbgfajh2234', }; let service: RegistrationService; @@ -52,12 +52,21 @@ it('Expected values from first password step', () => { spyOn(service, 'recoverPasswordStep1').and.returnValue(new Observable()); - expect(service.recoverPasswordStep1(recoverTransaction.email, recoverTransaction.username, recoverTransaction.captcha)).toEqual(new Observable()); + expect(service.recoverPasswordStep1( + recoverTransaction.email, + recoverTransaction.username, + recoverTransaction.captcha + )).toEqual(new Observable()); }); it('Expected values from second password step', () => { spyOn(service, 'recoverPasswordStep2').and.returnValue(new Observable()); - expect(service.recoverPasswordStep2(reset.new_password, reset.token, reset.transaction, reset.captcha)).toEqual(new Observable()); + expect(service.recoverPasswordStep2( + reset.new_password, + reset.token, + reset.transaction, + reset.captcha + )).toEqual(new Observable()); }); it('Expected values from recover username', () => { @@ -67,6 +76,11 @@ it('Expected values from registration', () => { spyOn(service, 'register').and.returnValue(new Observable()); - expect(service.register(registration.username, registration.email , registration.password , registration.captcha )).toEqual(new Observable()); + expect(service.register( + registration.username, + registration.email, + registration.password, + registration.captcha + )).toEqual(new Observable()); }); }); diff --git a/src/app/_services/registration.service.ts b/src/app/_services/registration.service.ts --- a/src/app/_services/registration.service.ts +++ b/src/app/_services/registration.service.ts @@ -29,9 +29,9 @@ .catch((error) => { return Observable.of( new RecoverTransactionError( - error.non_field_errors, - error.email, - error.captcha + error.error.non_field_errors, + error.error.email, + error.error.captcha ) ); }); @@ -53,11 +53,11 @@ .catch((error) => { return Observable.of( new ResetError( - error.non_field_errors, - error.new_password, - error.token, - error.transaction, - error.captcha + error.error.non_field_errors, + error.error.new_password, + error.error.token, + error.error.transaction, + error.error.captcha ) ); }); @@ -77,10 +77,10 @@ .catch((error) => { return Observable.of( new RecoverTransactionError( - error.non_field_errors, - error.username, - error.email, - error.captcha + error.error.non_field_errors, + error.error.username, + error.error.email, + error.error.captcha ) ); }); diff --git a/src/app/_shared/arealist/areaList.component.html b/src/app/_shared/arealist/areaList.component.html new file mode 100644 --- /dev/null +++ b/src/app/_shared/arealist/areaList.component.html @@ -0,0 +1,23 @@ + +
+
+
+

{{title}}

+
+
+

All Areas

+
+
+
+
+
+

{{area.displayname}}

+
+
+ add +
+
+
+
+
+
diff --git a/src/app/_shared/arealist/areaList.component.scss b/src/app/_shared/arealist/areaList.component.scss new file mode 100644 --- /dev/null +++ b/src/app/_shared/arealist/areaList.component.scss @@ -0,0 +1,68 @@ +.home { + &-area { + &-card { + width: 100%; + height: 15vw; + margin-top: 5%; + background: linear-gradient(0deg, #A2A2A2, #A2A2A2), linear-gradient(180deg, #A2A2A2 0%, #d3d3d3 99.99%); + box-shadow: 0px 0.986257px 7.39693px rgba(0, 0, 0, 0.3); + &-add { + width: 20vw; + height: 15vw; + margin-left: 5vw; + margin-top: 5%; + background: linear-gradient(0deg, #A2A2A2, #A2A2A2), linear-gradient(180deg, #A2A2A2 0%, #d3d3d3 99.99%); + box-shadow: 0px 0.986257px 7.39693px rgba(0, 0, 0, 0.3); + } + } + } + &-content { + &-container { + width: 100vw; + position: fixed; + top: 0; + left: 0; + } + } + &-input { + font-size: 100%; + width: 100%; + border: none; + outline: none; + box-shadow: none; + color: #A2A2A2; + margin: 0; + padding: 0; + max-width: 1000px; + overflow-y: auto; + } + &-container { + padding-left: 2rem; + padding-right: 2rem; + width: 100vw; + max-width: 1000px; + } + &-subtitle { + text-align: left; + font-family: 'Mukta', sans-serif; + font-weight: 500; + font-size: 2rem; + height: 40px; + display: flex; + justify-content: center; + align-items: center; + } + &-title { + font-size: 3rem; + text-align: left; + font-family: 'Mukta', sans-serif; + font-weight: 600; + max-width: 1000px; + } + &-comment { + &-container { + width: 100vw; + max-width: 1000px; + } + } +} diff --git a/src/app/_shared/arealist/areaList.component.ts b/src/app/_shared/arealist/areaList.component.ts new file mode 100644 --- /dev/null +++ b/src/app/_shared/arealist/areaList.component.ts @@ -0,0 +1,93 @@ +import { Component, OnInit, OnDestroy, Input } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { Subject } from 'rxjs/Subject'; +import { Area } from '../../_models/area'; +import { AreaService } from '../../_services/area.service'; +import { NavBarService } from '../../_services/navBar.service'; +import { RouteService } from '../../_services/route.service'; + +enum View { + home, + posts +} + +@Component({ + templateUrl: 'areaList.component.html', + styleUrls: ['./areaList.component.scss'], + selector: 'app-area-list' +}) +export class AreaListComponent implements OnInit, OnDestroy { + @Input() public showAdd = true; + allArea = new Area('_', 'All Posts', 0, 0); + areas = new Array(new Area('', '', 0, 0)); + currentView: View = View.home; + componentDestroyed: Subject = new Subject(); + loading = true; + title = 'Home'; + path = ''; + + constructor( + private route: ActivatedRoute, + private router: Router, + private areaService: AreaService, + private navBarService: NavBarService, + private routeService: RouteService + ) { } + + ngOnInit() { + this.route.url + .subscribe(r => { + if (r[0]) { + if (r[0].path === 'posts') { + this.path = r[0].path; + this.title = 'My Posts'; + this.currentView = View.posts; + } + } + }); + + this.areaService.getAreas() + .takeUntil(this.componentDestroyed) + .subscribe(areas => { + this.areas = []; + + for (let i = 0; i < areas.length; i++) { + this.areaService.getAreaRep(areas[i].name) + .takeUntil(this.componentDestroyed) + .subscribe(result => { + let area; + area = new Area( + areas[i].name, + areas[i].displayname, + result.reputation, + result.spread + ); + + this.areas.push(area); + this.loading = false; + }); + } + }); + } + + ngOnDestroy() { + this.componentDestroyed.next(true); + this.componentDestroyed.complete(); + } + + goto(a: Area, createPost?: boolean) { + this.navBarService.currentArea.next(a); + this.routeService.addNextRoute(this.path); + if (createPost) { + this.router.navigateByUrl(`create/${a.name}`); + } else if (this.currentView === View.home) { + this.router.navigateByUrl(`/areas/${a.name}`); + } else { + this.router.navigateByUrl(`${this.path}/${a.name}`); + } + } + + view() { + return View; + } +} diff --git a/src/app/_shared/imageUpload/imageUpload.component.html b/src/app/_shared/imageUpload/imageUpload.component.html new file mode 100644 --- /dev/null +++ b/src/app/_shared/imageUpload/imageUpload.component.html @@ -0,0 +1,23 @@ + +
+
+
+ keyboard_arrow_left +
+
+ Avatar of {{author?.name}} + Avatar of {{author?.name}} +
+
+ + +
+
+ +
+ +
+ +
+
+
diff --git a/src/app/_shared/imageUpload/imageUpload.component.scss b/src/app/_shared/imageUpload/imageUpload.component.scss new file mode 100644 --- /dev/null +++ b/src/app/_shared/imageUpload/imageUpload.component.scss @@ -0,0 +1,91 @@ +.imageUpload { + &-button { + width: 100%; + font-family: 'Mukta', sans-serif; + border: 1px solid #EA6C40; + border-radius: 4px; + font-weight: 700; + position: relative; + & input[type="file"]{ + -webkit-appearance:none; + position:absolute; + top:0; + left:0; + opacity:0; + width: 100%; + height: 100%; + } + &-group { + height: 25vh; + padding-left: 3rem; + padding-right: 3rem; + background: transparent !important; + width: 100%; + } + } + &-container { + padding-left: 2rem; + padding-right: 2rem; + width: 100vw; + max-width: 1000px; + } + &-image { + height: 50vh; + max-width: 1000px; + } + &-input { + width: 100%; + border: none; + outline: none; + box-shadow: none; + color: #A2A2A2; + margin: 0; + padding: 0; + max-width: 1000px; + overflow-y: auto; + } + &-post { + &-group { + width: 100%; + } + &-row { + width: 100%; + flex-wrap: wrap; + + &-icons { + padding-left: 5%; + padding-right: 5%; + } + } + &-card { + width: 47.5%; + height: 15vh; + padding-left: 2%; + padding-right: 2%; + margin-bottom: 5%; + background: linear-gradient(0deg, #A2A2A2, #A2A2A2), linear-gradient(180deg, #A2A2A2 0%, #d3d3d3 99.99%); + box-shadow: 0px 0.986257px 7.39693px rgba(0, 0, 0, 0.3); + &:nth-child(odd) { + margin-right: 5%; + } + } + } + &-subtitle { + text-align: left; + font-family: 'Mukta', sans-serif; + color: #A2A2A2; + font-weight: 500; + font-size: 2rem; + height: 40px; + display: flex; + justify-content: center; + align-items: center; + } + &-title { + font-size: 2rem; + text-align: left; + font-family: 'Mukta', sans-serif; + font-weight: 500; + max-width: 1000px; + } +} diff --git a/src/app/_shared/imageUpload/imageUpload.component.ts b/src/app/_shared/imageUpload/imageUpload.component.ts new file mode 100644 --- /dev/null +++ b/src/app/_shared/imageUpload/imageUpload.component.ts @@ -0,0 +1,80 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { MatSnackBar } from '@angular/material'; +import { Router } from '@angular/router'; +import { Subject } from 'rxjs/Subject'; +import { Author } from '../../_models/author'; +import { ProfileService } from '../../_services/profile.service'; +import { RouteService } from '../../_services/route.service'; + +declare const Compressor: any; + +@Component({ + templateUrl: 'imageUpload.component.html', + styleUrls: ['./imageUpload.component.scss'] +}) +export class ImageUploadComponent implements OnInit, OnDestroy { + author: Author; + componentDestroyed: Subject = new Subject(); + errors: any; + loading = true; + + constructor( + public snackBar: MatSnackBar, + private router: Router, + private profileService: ProfileService, + private routeService: RouteService + ) { } + + ngOnInit() { + this.profileService.getSelf() + .takeUntil(this.componentDestroyed) + .subscribe((self: Author) => { + this.author = self; + if (this.author.bio === '') { + this.author.bio = '*No Bio*'; + } + this.loading = false; + }); + } + + ngOnDestroy() { + this.componentDestroyed.next(true); + this.componentDestroyed.complete(); + } + + back() { + if (this.routeService.routes.length === 0) { + this.router.navigateByUrl(''); + } else { + this.router.navigateByUrl(this.routeService.getNextRoute()); + } + } + + + uploadImage() { + const self = this; + const file = (document.getElementById('image-upload')).files[0]; + const file2: any = new Compressor(file, { + quality: 0.8, + maxWidth: 500, + maxHeight: 500, + convertSize: 500000, + success(result: Blob) { + self.uploadImg(result); + } + }); + } + + uploadImg(r: Blob) { + this.profileService.setProfilePicture(r) + .takeUntil(this.componentDestroyed) + .subscribe((result2: Author) => { + if (!result2.getError()) { + this.author.avatar = result2.avatar; + } else { + this.errors = result2.getError(); + this.loading = false; + } + }); + } +} diff --git a/src/app/_shared/myPosts/myPosts.component.html b/src/app/_shared/myPosts/myPosts.component.html new file mode 100644 --- /dev/null +++ b/src/app/_shared/myPosts/myPosts.component.html @@ -0,0 +1,34 @@ +
+
+ keyboard_arrow_left +
+
+
+
+
+

My Posts

+

{{currentArea.displayname}}

+
+
+
+
+
+ image + hourglass_full + hourglass_empty + visibility_on + visibility_off + filter_none +
{{post.comments.length}}
+
+

+ ... +
+
+
+ +
+ +
+
+
diff --git a/src/app/_shared/myPosts/myPosts.component.scss b/src/app/_shared/myPosts/myPosts.component.scss new file mode 100644 --- /dev/null +++ b/src/app/_shared/myPosts/myPosts.component.scss @@ -0,0 +1,105 @@ +.profile { + &-button { + width: 100%; + font-family: 'Mukta', sans-serif; + border: 1px solid #EA6C40; + border-radius: 4px; + font-weight: 700; + position: relative; + & input[type="file"]{ + -webkit-appearance:none; + position:absolute; + top:0; + left:0; + opacity:0; + width: 100%; + height: 100%; + } + &-group { + height: 25vh; + padding-left: 3rem; + padding-right: 3rem; + background: transparent !important; + width: 100%; + } + } + &-container { + padding-left: 3rem; + padding-right: 3rem; + width: 100vw; + max-width: 1000px; + } + &-image { + position: relative; + height: 50vh; + width: 100%; + max-width: 1000px; + } + &-input { + width: 100%; + border: none; + outline: none; + box-shadow: none; + color: #A2A2A2; + margin: 0; + padding: 0; + max-width: 1000px; + overflow-y: auto; + } + &-post { + &-group { + width: 100%; + } + &-row { + width: 100%; + flex-wrap: wrap; + } + &-card { + width: 47.5%; + height: 15vh; + padding-left: 2%; + padding-right: 2%; + margin-bottom: 5%; + background: linear-gradient(0deg, #A2A2A2, #A2A2A2), linear-gradient(180deg, #A2A2A2 0%, #d3d3d3 99.99%); + box-shadow: 0px 0.986257px 7.39693px rgba(0, 0, 0, 0.3); + &:nth-child(odd) { + margin-right: 5%; + } + } + } + &-subtitle { + text-align: left; + font-family: 'Mukta', sans-serif; + color: #A2A2A2; + font-weight: 500; + font-size: 2rem; + height: 40px; + display: flex; + justify-content: center; + align-items: center; + } + &-title { + font-size: 3rem; + text-align: left; + font-family: 'Mukta', sans-serif; + font-weight: 600; + max-width: 1000px; + } +} + +#image { + display: none; + flex-direction: column; + box-sizing: border-box; + flex-direction: column; + place-content: center; + align-items: center; +} + +.marked { + overflow-y: scroll; +} + +span.markdown { + color: #ffffff !important; +} diff --git a/src/app/notificationArchive/notificationArchive.component.ts b/src/app/_shared/myPosts/myPosts.component.ts rename from src/app/notificationArchive/notificationArchive.component.ts rename to src/app/_shared/myPosts/myPosts.component.ts --- a/src/app/notificationArchive/notificationArchive.component.ts +++ b/src/app/_shared/myPosts/myPosts.component.ts @@ -1,40 +1,55 @@ -import { Component, OnInit, OnDestroy, NgModule, ChangeDetectorRef } from '@angular/core'; +import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core'; +import { FormGroup } from '@angular/forms'; +import { MatSnackBar } from '@angular/material'; import { Router, ActivatedRoute } from '@angular/router'; import { Subject } from 'rxjs/Subject'; -import { Area } from '../_models/area'; -import * as C from '../_models/constants'; -import { Post } from '../_models/post'; -import { NavBarService } from '../_services/navBar.service'; -import { NotificationService } from '../_services/notification.service'; -import { RouteService } from '../_services/route.service'; -import { NgxMasonryModule } from '../_modules/ngx-masonry/ngx-masonry.module'; +import { Account } from '../../_models/account'; +import { Area } from '../../_models/area'; +import { Author } from '../../_models/author'; +import { Ban } from '../../_models/ban'; +import { Choice } from '../../_models/choice'; +import * as C from '../../_models/constants'; +import { Post } from '../../_models/post'; +import { AreaService } from '../../_services/area.service'; +import { NavBarService } from '../../_services/navBar.service'; +import { PostService } from '../../_services/post.service'; +import { RouteService } from '../../_services/route.service'; @Component({ - templateUrl: 'notificationArchive.component.html' + templateUrl: 'myPosts.component.html', + styleUrls: ['./myPosts.component.scss'] }) -export class NotificationArchiveComponent implements OnInit, OnDestroy { +export class MyPostsComponent implements OnInit, OnDestroy { + account: Account; + author: Author; backupPosts: { [area: string]: Post[]; } = {}; + bans: Ban[] = []; + bioForm: FormGroup; + choices: Choice[]; componentDestroyed: Subject = new Subject(); - currentArea: string; - funPosts: Post[] = []; + currentArea: Area; + data: any; + editBio = false; + emailForm: FormGroup; + errors: any; imageArray: { [area: string]: string[]; } = {}; index = 1; - infoPosts: Post[] = []; limit = 10; loading = true; - model: any = {}; offset = 10; - searchArray: Post[] = []; - searching = false; + self: boolean; superPosts: { [area: string]: Post[]; } = {}; totalCount = 0; + url: string; constructor( private cdRef: ChangeDetectorRef, private route: ActivatedRoute, private router: Router, + public snackBar: MatSnackBar, + private areaService: AreaService, private navBarService: NavBarService, - private notificationService: NotificationService, + private postService: PostService, private routeService: RouteService ) { } @@ -54,7 +69,6 @@ } } } - this.loading = false; } private removeMarkdown(input: string) { @@ -77,7 +91,7 @@ .replace(/\[\^.+?\](\: .*?$)?/g, '') .replace(/\s{0,2}\[.*?\]: .*?$/g, '') // Remove images - .replace(/\!\[.*?\][\[\(].*?[\]\)]/g, '') + .replace(C.WF_IMAGE_REGEX, '') // Remove wildfyre images .replace(/(\[img: \d\])/gm, '') // Remove inline links @@ -102,28 +116,27 @@ ngOnInit() { this.route.params - .takeUntil(this.componentDestroyed) - .subscribe(params => { - if (params['index'] !== undefined) { - this.index = params['index']; - } - }); - - this.navBarService.currentArea + .takeUntil(this.componentDestroyed) + .subscribe(params => { + if (params['area'] !== undefined) { + this.areaService.getAreas() .takeUntil(this.componentDestroyed) - .subscribe((currentArea: Area) => { - if (currentArea.name !== '') { - this.currentArea = currentArea.name; - if (!this.superPosts[currentArea.name]) { - this.superPosts[currentArea.name] = []; + .subscribe((areas) => { + for (let i = 0; i <= areas.length - 1; i++) { + if (areas[i].name === params['area']) { + this.currentArea = areas[i]; } - if (!this.backupPosts[currentArea.name]) { - this.backupPosts[currentArea.name] = []; - } - this.loading = true; - const posts: Post[] = []; + } + + if (!this.superPosts[this.currentArea.name]) { + this.superPosts[this.currentArea.name] = []; + } + if (!this.backupPosts[this.currentArea.name]) { + this.backupPosts[this.currentArea.name] = []; + } + const posts: Post[] = []; - this.notificationService.getArchive(currentArea.name, this.limit, 0) + this.postService.getOwnPosts(this.currentArea.name, this.limit, 0) .takeUntil(this.componentDestroyed) .subscribe(superPost => { superPost.results.forEach((obj: any) => { @@ -131,20 +144,24 @@ }); // Removes binding to original 'superPost' variable - this.superPosts[currentArea.name] = JSON.parse(JSON.stringify(posts)); - this.backupPosts[currentArea.name] = posts; + this.superPosts[this.currentArea.name] = JSON.parse(JSON.stringify(posts)); + this.backupPosts[this.currentArea.name] = posts; this.totalCount = superPost.count; - this.imageInPosts(this.superPosts[currentArea.name], currentArea.name); + this.imageInPosts(this.superPosts[this.currentArea.name], this.currentArea.name); - for (let i = 0; i <= this.backupPosts[currentArea.name].length - 1; i++) { - this.backupPosts[currentArea.name][i].text = this.removeMarkdown(this.backupPosts[currentArea.name][i].text); + for (let i = 0; i <= this.backupPosts[this.currentArea.name].length - 1; i++) { + this.backupPosts[this.currentArea.name][i].text = this.removeMarkdown(this.backupPosts[this.currentArea.name][i].text); } + this.cdRef.detectChanges(); this.loading = false; }); - } - }); + + this.loading = false; + }); + } + }); } ngOnDestroy() { @@ -153,6 +170,7 @@ this.componentDestroyed.complete(); } + back() { if (this.routeService.routes.length === 0) { this.router.navigateByUrl(''); @@ -161,11 +179,11 @@ } } - getPosts(page: number) { + getPosts(page: any) { this.loading = true; const posts: Post[] = []; - this.notificationService.getArchive(this.currentArea, this.limit, (this.offset * page) - this.limit) + this.postService.getOwnPosts(this.currentArea.name, this.limit, (this.offset * page) - this.limit) .takeUntil(this.componentDestroyed) .subscribe(superPost => { superPost.results.forEach((obj: any) => { @@ -173,12 +191,12 @@ }); // Removes binding to original 'superPost' variable - this.superPosts[this.currentArea] = JSON.parse(JSON.stringify(posts)); - this.backupPosts[this.currentArea] = posts; - this.imageInPosts(this.superPosts[this.currentArea], this.currentArea); + this.superPosts[this.currentArea.name] = JSON.parse(JSON.stringify(posts)); + this.backupPosts[this.currentArea.name] = posts; + this.imageInPosts(this.superPosts[this.currentArea.name], this.currentArea.name); - for (let i = 0; i <= this.backupPosts[this.currentArea].length - 1; i++) { - this.backupPosts[this.currentArea][i].text = this.removeMarkdown(this.backupPosts[this.currentArea][i].text); + for (let i = 0; i <= this.backupPosts[this.currentArea.name].length - 1; i++) { + this.backupPosts[this.currentArea.name][i].text = this.removeMarkdown(this.backupPosts[this.currentArea.name][i].text); } this.index = page; this.totalCount = superPost.count; @@ -191,40 +209,4 @@ this.routeService.addNextRouteByIndex(this.index); this.router.navigateByUrl('/areas/' + this.currentArea + '/' + postID); } - -/* Removed as of D114 - searchInput() { - if (this.areaService.currentAreaName === 'fun') { - this.searchArray = []; - if (this.model.postText === '') { - this.searching = false; - this.cdRef.detectChanges(); - } else { - this.searching = true; - - for (let i = 0; i <= this.funPosts.length - 1; i++) { - if (this.funPosts[i].text.toLowerCase().includes(this.model.postText.toLowerCase())) { - this.searchArray.push(this.backupFunPosts[i]); - } - } - this.cdRef.detectChanges(); - } - } else { - this.searchArray = []; - if (this.model.postText === '') { - this.searching = false; - this.cdRef.detectChanges(); - } else { - this.searching = true; - - for (let i = 0; i <= this.infoPosts.length - 1; i++) { - if (this.infoPosts[i].text.toLowerCase().includes(this.model.postText.toLowerCase())) { - this.searchArray.push(this.backupInfoPosts[i]); - } - } - this.cdRef.detectChanges(); - } - } - } - */ } diff --git a/src/app/_shared/notifcations/notifications.component.html b/src/app/_shared/notifcations/notifications.component.html new file mode 100644 --- /dev/null +++ b/src/app/_shared/notifcations/notifications.component.html @@ -0,0 +1,16 @@ + +
+
+
+

Notifications

+
+
+
+

{{notification.post.text | slice:0:31}}…

+

{{notification.comments.length}}

+
+
+
+
+
+
diff --git a/src/app/_shared/notifcations/notifications.component.scss b/src/app/_shared/notifcations/notifications.component.scss new file mode 100644 --- /dev/null +++ b/src/app/_shared/notifcations/notifications.component.scss @@ -0,0 +1,68 @@ +.home { + &-area { + &-card { + width: 100%; + height: 15vw; + margin-top: 5%; + background: linear-gradient(0deg, #A2A2A2, #A2A2A2), linear-gradient(180deg, #A2A2A2 0%, #d3d3d3 99.99%); + box-shadow: 0px 0.986257px 7.39693px rgba(0, 0, 0, 0.3); + &-add { + width: 20vw; + height: 15vw; + margin-left: 5vw; + margin-top: 5%; + background: linear-gradient(0deg, #A2A2A2, #A2A2A2), linear-gradient(180deg, #A2A2A2 0%, #d3d3d3 99.99%); + box-shadow: 0px 0.986257px 7.39693px rgba(0, 0, 0, 0.3); + } + } + } + &-content { + &-container { + width: 100vw; + position: fixed; + top: 0; + left: 0; + } + } + &-input { + font-size: 100%; + width: 100%; + border: none; + outline: none; + box-shadow: none; + color: #A2A2A2; + margin: 0; + padding: 0; + max-width: 1000px; + overflow-y: auto; + } + &-container { + padding-left: 2rem; + padding-right: 2rem; + width: 100vw; + max-width: 1000px; + } + &-subtitle { + text-align: left; + font-family: 'Mukta', sans-serif; + font-weight: 500; + font-size: 2rem; + height: 40px; + display: flex; + justify-content: center; + align-items: center; + } + &-title { + font-size: 3rem; + text-align: left; + font-family: 'Mukta', sans-serif; + font-weight: 600; + max-width: 1000px; + } + &-comment { + &-container { + width: 100vw; + max-width: 1000px; + } + } +} diff --git a/src/app/notification/notification.component.spec.ts b/src/app/_shared/notifcations/notifications.component.spec.ts rename from src/app/notification/notification.component.spec.ts rename to src/app/_shared/notifcations/notifications.component.spec.ts --- a/src/app/notification/notification.component.spec.ts +++ b/src/app/_shared/notifcations/notifications.component.spec.ts @@ -4,22 +4,22 @@ import { MatCardModule, MatTabsModule, MatDialogModule, MatProgressSpinnerModule, MatSnackBarModule } from '@angular/material'; import { Router, ActivatedRoute, RouterModule } from '@angular/router'; import { Observable } from 'rxjs'; -import { Author } from '../_models/author'; -import { Comment } from '../_models/comment'; -import { Notification } from '../_models/notification'; -import { NotificationPost } from '../_models/notificationPost'; -import { Post } from '../_models/post'; -import { SuperNotification } from '../_models/superNotification'; -import { AuthenticationService } from '../_services/authentication.service'; -import { NotificationService } from '../_services/notification.service'; -import { RouteService } from '../_services/route.service'; -import { NavBarService } from '../_services/navBar.service'; -import { NotificationComponent } from './notification.component'; +import { Author } from '../../_models/author'; +import { Comment } from '../../_models/comment'; +import { Notification } from '../../_models/notification'; +import { NotificationPost } from '../../_models/notificationPost'; +import { Post } from '../../_models/post'; +import { SuperNotification } from '../../_models/superNotification'; +import { AuthenticationService } from '../../_services/authentication.service'; +import { NotificationService } from '../../_services/notification.service'; +import { RouteService } from '../../_services/route.service'; +import { NavBarService } from '../../_services/navBar.service'; +import { NotificationsComponent } from './notifications.component'; import { NgxPaginationModule } from 'ngx-pagination'; describe('NotificationComponent', () => { - let comp: NotificationComponent; - let fixture: ComponentFixture; + let comp: NotificationsComponent; + let fixture: ComponentFixture; beforeEach(() => { const routerStub = { @@ -47,7 +47,7 @@ const routeServiceStub = {}; TestBed.configureTestingModule({ - declarations: [ NotificationComponent ], + declarations: [ NotificationsComponent ], providers: [ { provide: Router, useValue: routerStub }, { provide: ActivatedRoute, useValue: activatedRouteStub }, @@ -57,9 +57,10 @@ { provide: RouteService, useValue: routeServiceStub }, { provide: ComponentFixtureAutoDetect, useValue: true } ], - imports: [ MatCardModule, RouterModule, MatTabsModule, NgxPaginationModule, MatDialogModule, MatProgressSpinnerModule, MatSnackBarModule ], + imports: [ MatCardModule, RouterModule, MatTabsModule, NgxPaginationModule, MatDialogModule, + MatProgressSpinnerModule, MatSnackBarModule ], }).compileComponents(); - fixture = TestBed.createComponent(NotificationComponent); + fixture = TestBed.createComponent(NotificationsComponent); comp = fixture.componentInstance; }); diff --git a/src/app/notification/notification.component.ts b/src/app/_shared/notifcations/notifications.component.ts rename from src/app/notification/notification.component.ts rename to src/app/_shared/notifcations/notifications.component.ts --- a/src/app/notification/notification.component.ts +++ b/src/app/_shared/notifcations/notifications.component.ts @@ -2,18 +2,19 @@ import { MatDialog, MatDialogRef, MatSnackBar } from '@angular/material'; import { Router, ActivatedRoute } from '@angular/router'; import { Subject } from 'rxjs/Subject'; -import { ConfirmDeletionDialogComponent } from '../_dialogs/confirmDeletion.dialog.component'; -import { Notification } from '../_models/notification'; -import { Post } from '../_models/post'; -import { SuperNotification } from '../_models/superNotification'; -import { NavBarService } from '../_services/navBar.service'; -import { NotificationService } from '../_services/notification.service'; -import { RouteService } from '../_services/route.service'; +import { ConfirmDeletionDialogComponent } from '../../_dialogs/confirmDeletion.dialog.component'; +import { Notification } from '../../_models/notification'; +import { Post } from '../../_models/post'; +import { SuperNotification } from '../../_models/superNotification'; +import { NavBarService } from '../../_services/navBar.service'; +import { NotificationService } from '../../_services/notification.service'; +import { RouteService } from '../../_services/route.service'; @Component({ - templateUrl: 'notification.component.html' + templateUrl: 'notifications.component.html', + styleUrls: ['./notifications.component.scss'] }) -export class NotificationComponent implements OnInit, OnDestroy { +export class NotificationsComponent implements OnInit, OnDestroy { archivedPosts: Post[] = []; componentDestroyed: Subject = new Subject(); index = 1; diff --git a/src/app/_shared/password/password.component.html b/src/app/_shared/password/password.component.html new file mode 100644 --- /dev/null +++ b/src/app/_shared/password/password.component.html @@ -0,0 +1,63 @@ + +
+
+
+ keyboard_arrow_left +
+
+

Change Password

+
+
+

Passwords must contain at least 8 characters and be alphanumeric (At least 1 letter and 1 number)

+
+
+
+
+

{{err}}

+
+
+
+ +
+
+

Password is required

+
+
+
+

{{err}}

+
+
+ +
+ +
+
+

Password is required

+
+
+
+

{{err}}

+
+
+ +
+ +
+
+

Password is required

+
+
+
+

{{err}}

+
+
+ +
+ +
+
+ +
+
+
+
diff --git a/src/app/_shared/password/password.component.scss b/src/app/_shared/password/password.component.scss new file mode 100644 --- /dev/null +++ b/src/app/_shared/password/password.component.scss @@ -0,0 +1,54 @@ +.password { + &-button { + width: 100%; + font-family: 'Mukta', sans-serif; + border: 1px solid #EA6C40; + border-radius: 4px; + font-weight: 700; + position: relative; + & input[type="file"]{ + -webkit-appearance:none; + position:absolute; + top:0; + left:0; + opacity:0; + width: 100%; + height: 100%; + } + &-group { + height: 25vh; + padding-left: 3rem; + padding-right: 3rem; + background: transparent !important; + width: 100%; + } + } + &-container { + padding-left: 2rem; + padding-right: 2rem; + width: 100vw; + max-width: 1000px; + } + &-input { + width: 100%; + border: none; + outline: none; + box-shadow: none; + color: #A2A2A2; + margin: 0; + padding: 0; + max-width: 1000px; + overflow-y: auto; + } + &-title { + font-size: 3rem; + text-align: left; + font-family: 'Mukta', sans-serif; + font-weight: 600; + max-width: 1000px; + } +} + +p { + color:#A2A2A2; +} diff --git a/src/app/_shared/password/password.component.ts b/src/app/_shared/password/password.component.ts new file mode 100644 --- /dev/null +++ b/src/app/_shared/password/password.component.ts @@ -0,0 +1,114 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { FormControl, FormGroup } from '@angular/forms'; +import { MatSnackBar } from '@angular/material'; +import { Router } from '@angular/router'; +import { Subject } from 'rxjs/Subject'; +import { Account } from '../../_models/account'; +import { AuthenticationService } from '../../_services/authentication.service'; +import { ProfileService } from '../../_services/profile.service'; +import { RouteService } from '../../_services/route.service'; + +@Component({ + templateUrl: 'password.component.html', + styleUrls: ['./password.component.scss'] +}) +export class PasswordComponent implements OnInit, OnDestroy { + account: Account; + componentDestroyed: Subject = new Subject(); + errors: any; + loading = true; + passwordForm: FormGroup; + self: boolean; + + constructor( + public snackBar: MatSnackBar, + private router: Router, + private authenticationService: AuthenticationService, + private profileService: ProfileService, + private routeService: RouteService + ) { } + + ngOnInit() { + this.passwordForm = new FormGroup({ + 'oldPassword': new FormControl(''), + 'password': new FormControl(''), + 'password2': new FormControl(''), + }); + this.loading = false; + } + + ngOnDestroy() { + this.componentDestroyed.next(true); + this.componentDestroyed.complete(); + } + + back() { + if (this.routeService.routes.length === 0) { + this.router.navigateByUrl(''); + } else { + this.router.navigateByUrl(this.routeService.getNextRoute()); + } + } + + changePassword() { + this.loading = true; + + if (this.passwordForm.valid) { + this.authenticationService.login(this.account.username, this.passwordForm.controls.oldPassword.value) + .takeUntil(this.componentDestroyed) + .subscribe(result => { + if (!result.getError()) { + if (this.passwordForm.controls.password.value === this.passwordForm.controls.password2.value) { + this.profileService.setPassword(this.passwordForm.controls.password.value) + .takeUntil(this.componentDestroyed) + .subscribe(result2 => { + if (!result2.getError()) { + this.authenticationService.login(this.account.username, this.passwordForm.controls.password.value) + .takeUntil(this.componentDestroyed) + .subscribe(result3 => { + if (!result3.getError()) { + this.loading = false; + this.passwordForm.controls.oldPassword.setValue(''); + this.passwordForm.controls.password.setValue(''); + this.passwordForm.controls.password2.setValue(''); + this.snackBar.open('Password changed successfully', 'Close', { + duration: 3000 + }); + } else { + this.loading = false; + this.snackBar.open('Error could not set token', 'Close', { + duration: 3000 + }); + } + }); + } else { + this.errors = result2.getError(); + this.loading = false; + this.snackBar.open('You did not follow the requirements', 'Close', { + duration: 3000 + }); + } + }); + + } else { + this.loading = false; + this.snackBar.open('Your new passwords do not match', 'Close', { + duration: 3000 + }); + } + } else { + this.errors = result.getError(); + this.loading = false; + this.snackBar.open('This is not your current password', 'Close', { + duration: 3000 + }); + } + }); + } else { + this.loading = false; + this.snackBar.open('Your information is incorrect', 'Close', { + duration: 3000 + }); + } + } +} diff --git a/src/app/_shared/post/post.component.html b/src/app/_shared/post/post.component.html new file mode 100644 diff --git a/src/app/_shared/post/post.component.scss b/src/app/_shared/post/post.component.scss new file mode 100644 diff --git a/src/app/_shared/post/post.component.ts b/src/app/_shared/post/post.component.ts new file mode 100644 diff --git a/src/app/_shared/profile/profile.component.html b/src/app/_shared/profile/profile.component.html new file mode 100644 --- /dev/null +++ b/src/app/_shared/profile/profile.component.html @@ -0,0 +1,107 @@ + +
+
+ Avatar of {{author?.name}} + Avatar of {{author?.name}} +
+
+
+ +
+
+

Password

+

Info

+
+
+ +
+
+

{{author?.name}}

+
+ +
+ +
+ +
+
+ +
+
+ +
+ +
+ +
+
+ +
+
+ +
+ +
+
+

+
+
+
+

{{err}}

+
+
+
+
+
+ + diff --git a/src/app/_shared/profile/profile.component.scss b/src/app/_shared/profile/profile.component.scss new file mode 100644 --- /dev/null +++ b/src/app/_shared/profile/profile.component.scss @@ -0,0 +1,119 @@ +.profile { + &-button { + width: 100%; + font-family: 'Mukta', sans-serif; + border: 1px solid #EA6C40; + border-radius: 4px; + font-weight: 700; + position: relative; + & input[type="file"]{ + -webkit-appearance:none; + position:absolute; + top:0; + left:0; + opacity:0; + width: 100%; + height: 100%; + } + &-group { + height: 25vh; + padding-left: 3rem; + padding-right: 3rem; + background: transparent !important; + width: 100%; + } + } + &-container { + padding-left: 3rem; + padding-right: 3rem; + width: 100vw; + max-width: 1000px; + position: relative; + margin-top: -50vh; + left: 0; + background-image: linear-gradient( + to bottom, + hsla(0, 0%, 100%, 0) 0%, + hsla(0, 0%, 100%, 0.143) 4.4%, + hsla(0, 0%, 100%, 0.274) 7.7%, + hsla(0, 0%, 100%, 0.392) 10.4%, + hsla(0, 0%, 100%, 0.498) 12.7%, + hsla(0, 0%, 100%, 0.593) 14.8%, + hsla(0, 0%, 100%, 0.676) 17.2%, + hsla(0, 0%, 100%, 0.749) 20.1%, + hsla(0, 0%, 100%, 0.811) 23.9%, + hsla(0, 0%, 100%, 0.864) 28.8%, + hsla(0, 0%, 100%, 0.907) 35.2%, + hsla(0, 0%, 100%, 0.942) 43.3%, + hsla(0, 0%, 100%, 0.968) 53.6%, + hsla(0, 0%, 100%, 0.986) 66.3%, + hsla(0, 0%, 100%, 0.997) 81.6%, + hsl(0, 0%, 100%) 100% + ); + } + &-image { + position: relative; + height: 50vh; + width: 100%; + max-width: 1000px; + } + &-input { + width: 100%; + border: none; + outline: none; + box-shadow: none; + color: #A2A2A2; + margin: 0; + padding: 0; + max-width: 1000px; + overflow-y: auto; + } + &-post { + &-group { + width: 100%; + } + &-row { + width: 100%; + flex-wrap: wrap; + + &-icons { + padding-left: 5%; + padding-right: 5%; + } + } + &-card { + width: 47.5%; + height: 15vh; + padding-left: 2%; + padding-right: 2%; + margin-bottom: 5%; + background: linear-gradient(0deg, #A2A2A2, #A2A2A2), linear-gradient(180deg, #A2A2A2 0%, #d3d3d3 99.99%); + box-shadow: 0px 0.986257px 7.39693px rgba(0, 0, 0, 0.3); + &:nth-child(odd) { + margin-right: 5%; + } + } + } + &-subtitle { + text-align: left; + font-family: 'Mukta', sans-serif; + color: #A2A2A2; + font-weight: 500; + font-size: 2rem; + height: 40px; + display: flex; + justify-content: center; + align-items: center; + } + &-title { + font-size: 2rem; + text-align: left; + font-family: 'Mukta', sans-serif; + font-weight: 500; + max-width: 1000px; + } +} + +.marked { + overflow-y: scroll; +} diff --git a/src/app/profile/profile.component.spec.ts b/src/app/_shared/profile/profile.component.spec.ts rename from src/app/profile/profile.component.spec.ts rename to src/app/_shared/profile/profile.component.spec.ts --- a/src/app/profile/profile.component.spec.ts +++ b/src/app/_shared/profile/profile.component.spec.ts @@ -42,7 +42,7 @@ const authenticationServiceStub = { token: 'token' }; - const reasonServiceStub = {} + const reasonServiceStub = {}; const profileServiceStub = { getUser: (id: number) => { if (id !== 1) { diff --git a/src/app/_shared/profile/profile.component.ts b/src/app/_shared/profile/profile.component.ts new file mode 100644 --- /dev/null +++ b/src/app/_shared/profile/profile.component.ts @@ -0,0 +1,249 @@ +import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core'; +import { FormControl, FormGroup } from '@angular/forms'; +import { MatSnackBar } from '@angular/material'; +import { ActivatedRoute, Router } from '@angular/router'; +import { Subject } from 'rxjs/Subject'; +import { Account } from '../../_models/account'; +import { Author } from '../../_models/author'; +import { Ban } from '../../_models/ban'; +import { Post } from '../../_models/post'; +import { SuperBan } from '../../_models/superBan'; +import { ProfileService } from '../../_services/profile.service'; +import { RouteService } from '../../_services/route.service'; + +declare const Compressor: any; + +@Component({ + templateUrl: 'profile.component.html', + styleUrls: ['./profile.component.scss'] +}) +export class ProfileComponent implements OnInit, OnDestroy { + account: Account; + author: Author; + bans: Ban[] = []; + bioForm: FormGroup; + componentDestroyed: Subject = new Subject(); + editBio = false; + emailForm: FormGroup; + errors: any; + imageArray: { [area: string]: string[]; } = {}; + index = 1; + limit = 10; + loading = true; + offset = 10; + passwordForm: FormGroup; + path = ''; + self: boolean; + superPosts: { [area: string]: Post[]; } = {}; + totalCount = 0; + url: string; + + constructor( + private route: ActivatedRoute, + private cdRef: ChangeDetectorRef, + private router: Router, + public snackBar: MatSnackBar, + private profileService: ProfileService, + private routeService: RouteService + ) { } + + ngOnInit() { + this.route.url + .subscribe(r => { + if (r[0]) { + this.path = r[0].path; + } + }); + + this.emailForm = new FormGroup({ + 'email': new FormControl(''), + }); + + this.bioForm = new FormGroup({ + 'bio': new FormControl(''), + }); + + this.profileService.getSelf() + .takeUntil(this.componentDestroyed) + .subscribe((self: Author) => { + this.author = self; + if (this.author.bio === '') { + this.author.bio = '*No Bio*'; + } + this.loading = false; + this.bioForm.controls.bio.setValue(this.author.bio); + }); + + this.profileService.getAccount() + .takeUntil(this.componentDestroyed) + .subscribe((self: Account) => { + this.account = self; + if (this.account.email === '') { + this.account.email = '*Please verify your email*'; + } + this.emailForm.controls.email.setValue(this.account.email); + }); + + this.profileService.getBans(this.limit, (this.index * this.limit) - this.limit) + .takeUntil(this.componentDestroyed) + .subscribe((superBan: SuperBan) => { + superBan.results.forEach((obj: any) => { + this.bans.push(Ban.parse(obj)); + }); + this.totalCount = superBan.count; + }); + } + + ngOnDestroy() { + this.componentDestroyed.next(true); + this.componentDestroyed.complete(); + } + + getBans(page: number) { + this.loading = true; + this.bans = []; + + this.profileService.getBans(this.limit, (this.offset * page) - this.limit) + .takeUntil(this.componentDestroyed) + .subscribe(superBan => { + + superBan.results.forEach((obj: any) => { + this.bans.push(Ban.parse(obj)); + }); + + this.index = page; + this.totalCount = superBan.count; + this.cdRef.detectChanges(); + this.loading = false; + }); + } + + goto(s: string) { + this.routeService.addNextRoute(this.path); + + if (s === 'password') { + this.router.navigateByUrl('/tools/password'); + } else { + this.router.navigateByUrl('/tools/image-upload'); + } + } + + info(event: any) { + event.stopPropagation(); + this.snackBar.open('Touch the item you want to edit', 'Close', { + duration: 3000 + }); + } + + infoNo() { + this.snackBar.open('You can not edit this', 'Close', { + duration: 3000 + }); + } + + setBio() { + this.loading = true; + + if (this.bioForm.valid) { + this.profileService.setBio(this.author, this.bioForm.controls.bio.value) + .takeUntil(this.componentDestroyed) + .subscribe(result => { + if (!result.getError()) { + this.author = result; + this.snackBar.open('Bio changed successfully', 'Close', { + duration: 3000 + }); + this.toggleBio(); + this.loading = false; + } else { + this.errors = result.getError(); + this.loading = false; + } + }); + } else { + this.loading = false; + this.snackBar.open('Your information is incorrect', 'Close', { + duration: 3000 + }); + } + } + + setEmail() { + this.loading = true; + if (this.bioForm.valid) { + this.profileService.setEmail(this.emailForm.controls.email.value) + .takeUntil(this.componentDestroyed) + .subscribe(result => { + if (!result.getError()) { + this.account = result; + this.snackBar.open('We just sent you a verification email, you must verify your email for it to be set', 'Close', { + duration: 3000 + }); + this.undoEmail(); + this.loading = false; + } else { + this.errors = result.getError(); + this.loading = false; + } + }); + } else { + this.loading = false; + this.snackBar.open('Your information is incorrect', 'Close', { + duration: 3000 + }); + } + } + + toggleBio() { + this.editBio = !this.editBio; + + if (!this.editBio) { + this.bioForm.controls.bio.setValue(this.author.bio); + } + } + + undoEmail() { + this.emailForm.controls.email.setValue(this.account.email); + } + + viewProfile() { + this.routeService.addNextRoute(this.router.url); + this.router.navigateByUrl('/user/' + this.author.user); + } + + /* Removed as of D114 + searchInput() { + if (this.areaService.currentAreaName === 'fun') { + this.searchArray = []; + if (this.model.postText === '') { + this.searching = false; + this.cdRef.detectChanges(); + } else { + this.searching = true; + + for (let i = 0; i <= this.funPosts.length - 1; i++) { + if (this.funPosts[i].text.toLowerCase().includes(this.model.postText.toLowerCase())) { + this.searchArray.push(this.backupFunPosts[i]); + } + } + this.cdRef.detectChanges(); + } + } else { + this.searchArray = []; + if (this.model.postText === '') { + this.searching = false; + this.cdRef.detectChanges(); + } else { + this.searching = true; + + for (let i = 0; i <= this.infoPosts.length - 1; i++) { + if (this.infoPosts[i].text.toLowerCase().includes(this.model.postText.toLowerCase())) { + this.searchArray.push(this.backupInfoPosts[i]); + } + } + this.cdRef.detectChanges(); + } + } + } + */ +} diff --git a/src/app/app.component.html b/src/app/app.component.html --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,3 +1,2 @@ Loading.. -




diff --git a/src/app/app.component.ts b/src/app/app.component.ts --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -23,7 +23,7 @@ if (this.authenticationService.token) { this.areaService.getAreas() .takeUntil(this.componentDestroyed) - .subscribe(result => { + .subscribe(() => { this.loading = false; this.cdRef.detectChanges(); }); diff --git a/src/app/app.module.ts b/src/app/app.module.ts --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,11 +1,12 @@ // Angular Modules import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserModule } from '@angular/platform-browser'; -import { FormsModule } from '@angular/forms'; +import { FlexLayoutModule } from '@angular/flex-layout'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { HttpClientModule } from '@angular/common/http'; import { MatButtonModule, MatCardModule, MatCheckboxModule, MatDialogModule, MatExpansionModule, MatIconModule, MatInputModule, MatListModule, MatMenuModule, MatProgressSpinnerModule, MatRadioModule, - MatSelectModule, MatSidenavModule, MatSlideToggleModule, MatSnackBarModule, MatTabsModule } from '@angular/material'; + MatSelectModule, MatSidenavModule, MatSlideToggleModule, MatSnackBarModule, MatTabsModule, MatTooltipModule } from '@angular/material'; import { NgModule } from '@angular/core'; // Core Components @@ -16,32 +17,25 @@ import { HomeComponent } from './home/home.component'; import { LoginComponent } from './login/login.component'; import { NavBarComponent } from './navBar/navBar.component'; -import { NotificationArchiveComponent } from './notificationArchive/notificationArchive.component'; -import { NotificationComponent } from './notification/notification.component'; -import { PostViewComponent } from './postView/postView.component'; -import { ProfileComponent } from './profile/profile.component'; -import { ProfileViewComponent } from './profileView/profileView.component'; -import { RecoverComponent } from './recover/recover.component'; -import { RecoverPasswordComponent } from './recoverPassword/recoverPassword.component'; -import { RegisterComponent } from './register/register.component'; -import { RegisterSuccessComponent } from './registerSuccess/registerSuccess.component'; -import { UserPostsComponent } from './userPosts/userPosts.component'; + +// Shared Components +import { AreaListComponent } from './_shared/areaList/areaList.component'; +import { ImageUploadComponent } from './_shared/imageUpload/imageUpload.component'; +import { MyPostsComponent } from './_shared/myPosts/myPosts.component'; +import { NotificationsComponent } from './_shared/notifcations/notifications.component'; +import { PasswordComponent } from './_shared/password/password.component'; +import { ProfileComponent } from './_shared/profile/profile.component'; // Core Dialogs -import { AvatarDialogComponent } from './_dialogs/avatar.dialog.component'; -import { BioDialogComponent } from './_dialogs/bio.dialog.component'; import { ConfirmDeletionDialogComponent } from './_dialogs/confirmDeletion.dialog.component'; -import { EmailDialogComponent } from './_dialogs/email.dialog.component'; import { FlagDialogComponent } from './_dialogs/flag.dialog.component'; import { LogoutDialogComponent } from './_dialogs/logout.dialog.component'; -import { PasswordDialogComponent } from './_dialogs/password.dialog.component'; import { PictureDialogComponent } from './_dialogs/picture.dialog.component'; import { PicturesDialogComponent } from './_dialogs/pictures.dialog.component'; import { ShareDialogComponent } from './_dialogs/share.dialog.component'; import { YouTubeDialogComponent } from './_dialogs/youtube.dialog.component'; // Core Modules -import { NgxMasonryModule } from './_modules/ngx-masonry/ngx-masonry.module'; import { ShareModule } from './_modules/ng2share/share.module'; // Core Pipes @@ -68,6 +62,7 @@ import { ClipboardModule } from 'ngx-clipboard'; import 'hammerjs'; import { ImageCropperModule } from 'ngx-img-cropper'; +import { NgxImageCompressService } from 'ngx-image-compress'; import { NgxPaginationModule } from 'ngx-pagination'; import { ReCaptchaModule } from 'angular2-recaptcha'; @@ -76,13 +71,11 @@ // forRoot Angulartics2Module.forRoot([ Angulartics2Piwik ]), - // Core Modules - NgxMasonryModule, - // Modules BrowserAnimationsModule, BrowserModule, FormsModule, + FlexLayoutModule, HttpClientModule, ImageCropperModule, MatButtonModule, @@ -101,6 +94,8 @@ MatSlideToggleModule, MatSnackBarModule, MatTabsModule, + MatTooltipModule, + ReactiveFormsModule, Routing, // Third Party Modules @@ -120,25 +115,19 @@ HomeComponent, LoginComponent, NavBarComponent, - NotificationArchiveComponent, - NotificationComponent, - PostViewComponent, + + // Shared Components + AreaListComponent, + ImageUploadComponent, + MyPostsComponent, + NotificationsComponent, + PasswordComponent, ProfileComponent, - ProfileViewComponent, - RecoverComponent, - RecoverPasswordComponent, - RegisterComponent, - RegisterSuccessComponent, - UserPostsComponent, // Dialogs - AvatarDialogComponent, - BioDialogComponent, ConfirmDeletionDialogComponent, - EmailDialogComponent, FlagDialogComponent, LogoutDialogComponent, - PasswordDialogComponent, PictureDialogComponent, PicturesDialogComponent, ShareDialogComponent, @@ -146,7 +135,7 @@ // Pipes MarkedPipe - ], + ], providers: [ AreaService, AuthGuard, @@ -155,6 +144,7 @@ FlagService, HttpService, NavBarService, + NgxImageCompressService, NotificationService, PostService, ProfileService, @@ -163,13 +153,9 @@ RouteService ], entryComponents: [ - AvatarDialogComponent, - BioDialogComponent, ConfirmDeletionDialogComponent, - EmailDialogComponent, FlagDialogComponent, LogoutDialogComponent, - PasswordDialogComponent, PictureDialogComponent, PicturesDialogComponent, ShareDialogComponent, diff --git a/src/app/app.routing.ts b/src/app/app.routing.ts --- a/src/app/app.routing.ts +++ b/src/app/app.routing.ts @@ -1,40 +1,35 @@ import { Routes, RouterModule } from '@angular/router'; +import { AreaListComponent } from './_shared/areaList/areaList.component'; import { Component404Component } from './404component/404.component'; import { DraftsComponent } from './drafts/drafts.component'; import { CreatePostComponent } from './createPost/createPost.component'; import { HomeComponent } from './home/home.component'; +import { ImageUploadComponent } from './_shared/imageUpload/imageUpload.component'; import { LoginComponent } from './login/login.component'; -import { NotificationArchiveComponent } from './notificationArchive/notificationArchive.component'; -import { NotificationComponent } from './notification/notification.component'; -import { RecoverComponent } from './recover/recover.component'; -import { RecoverPasswordComponent } from './recoverPassword/recoverPassword.component'; -import { RegisterComponent } from './register/register.component'; -import { RegisterSuccessComponent } from './registerSuccess/registerSuccess.component'; -import { PostViewComponent } from './postView/postView.component'; -import { ProfileComponent } from './profile/profile.component'; -import { ProfileViewComponent } from './profileView/profileView.component'; -import { UserPostsComponent } from './userPosts/userPosts.component'; +import { MyPostsComponent } from './_shared/myPosts/myPosts.component'; +import { NotificationsComponent } from './_shared/notifcations/notifications.component'; +import { PasswordComponent } from './_shared/password/password.component'; +import { ProfileComponent } from './_shared/profile/profile.component'; import { AuthGuard } from './_guards/auth.guard'; const appRoutes: Routes = [ - { path: '', component: HomeComponent, canActivate: [AuthGuard] }, - { path: 'areas/:area/:id', component: PostViewComponent }, - { path: 'areas/:area/:id/:comments', component: PostViewComponent }, + { path: '', component: AreaListComponent, canActivate: [AuthGuard] }, + { path: 'areas/:area', component: HomeComponent, canActivate: [AuthGuard] }, + { path: 'areas/:area/:id', component: HomeComponent }, + { path: 'areas/:area/:id/:comments', component: HomeComponent }, { path: 'create', component: CreatePostComponent, canActivate: [AuthGuard] }, { path: 'create/:id', component: CreatePostComponent, canActivate: [AuthGuard] }, { path: 'drafts', component: DraftsComponent, canActivate: [AuthGuard] }, { path: 'login', component: LoginComponent }, - { path: 'notifications', component: NotificationComponent, canActivate: [AuthGuard] }, - { path: 'notifications/:index', component: NotificationComponent, canActivate: [AuthGuard] }, - { path: 'notifications/archive/:index', component: NotificationArchiveComponent, canActivate: [AuthGuard] }, - { path: 'posts', component: UserPostsComponent, canActivate: [AuthGuard] }, - { path: 'posts/:index', component: UserPostsComponent, canActivate: [AuthGuard] }, + { path: 'notifications', component: NotificationsComponent, canActivate: [AuthGuard] }, + { path: 'notifications/:index', component: NotificationsComponent, canActivate: [AuthGuard] }, + { path: 'notifications/archive/:index', component: NotificationsComponent, canActivate: [AuthGuard] }, + { path: 'posts', component: AreaListComponent, canActivate: [AuthGuard] }, + { path: 'posts/:area', component: MyPostsComponent, canActivate: [AuthGuard] }, { path: 'profile', component: ProfileComponent, canActivate: [AuthGuard] }, - { path: 'recover', component: RecoverComponent }, - { path: 'recover/password/:trans', component: RecoverPasswordComponent }, - { path: 'register', component: RegisterComponent }, - { path: 'register/success', component: RegisterSuccessComponent }, - { path: 'user/:id', component: ProfileViewComponent }, + { path: 'tools/image-upload', component: ImageUploadComponent, canActivate: [AuthGuard] }, + { path: 'tools/password', component: PasswordComponent, canActivate: [AuthGuard] }, + { path: 'user/:id', component: ProfileComponent }, // otherwise redirect to 404 { path: '**', component: Component404Component } diff --git a/src/app/createPost/createPost.component.ts b/src/app/createPost/createPost.component.ts --- a/src/app/createPost/createPost.component.ts +++ b/src/app/createPost/createPost.component.ts @@ -389,7 +389,7 @@ .replace('m.', '') .replace('youtube.com/watch?v=', '') .replace('youtu.be/', '') - .replace('youtube.com/', '') + .replace('youtube.com/', ''); if (result.url.indexOf('?') !== -1) { result.url = result.url.slice(0, result.url.indexOf('?')); @@ -397,7 +397,7 @@ this.post.text = this.post.text === undefined ? `[![${result.altText}](https://img.youtube.com/vi/${result.url}/0.jpg)](https://www.youtube.com/watch?v=${result.url})\n` : - `[![${result.altText}](https://img.youtube.com/vi/${result.url}/0.jpg)](https://www.youtube.com/watch?v=${result.url})\n${this.post.text}` +`[![${result.altText}](https://img.youtube.com/vi/${result.url}/0.jpg)](https://www.youtube.com/watch?v=${result.url})\n${this.post.text}`; } }); } diff --git a/src/app/drafts/drafts.component.html b/src/app/drafts/drafts.component.html --- a/src/app/drafts/drafts.component.html +++ b/src/app/drafts/drafts.component.html @@ -7,7 +7,7 @@ - + diff --git a/src/app/home/home.component.html b/src/app/home/home.component.html --- a/src/app/home/home.component.html +++ b/src/app/home/home.component.html @@ -1,4 +1,109 @@ - + +
+
+ +
+ +
+
+ + +
+
+
+ +
+ keyboard_arrow_left +

{{currentArea.displayname}}

+
+
+

Info

+
+
+ + +
+ + +
+ outlined_flag + Avatar of {{post.author.name}} + Avatar of {{post.author.name}} +
+

{{post.author.name}}

+
+

{{post.created}}

+
+
+ info + bookmark_border + bookmark +
+ + +
+ keyboard_arrow_up + keyboard_arrow_down +
+ + +
+

Comments: {{post.comments.length}}

+ keyboard_arrow_up +
+
+
+ + +
+
+
+
+

Comments: {{post.comments.length}}

+ keyboard_arrow_down +
+ +
+
+
+
+
+

{{comment.author.name}} {{comment.created}}

+
+ +
+
+
+
+
+ +
+
+
+
+

{{err}}

+
+
+
+ +
+
+

Comment is required

+
+
+
+

{{err}}

+
+
+
+ +

Send

+
+
+
+
+ + diff --git a/src/app/home/home.component.scss b/src/app/home/home.component.scss new file mode 100644 --- /dev/null +++ b/src/app/home/home.component.scss @@ -0,0 +1,120 @@ +.home { + &-area { + &-card { + width: 80vw; + height: 15vw; + margin-top: 5%; + background: linear-gradient(0deg, #A2A2A2, #A2A2A2), linear-gradient(180deg, #A2A2A2 0%, #d3d3d3 99.99%); + box-shadow: 0px 0.986257px 7.39693px rgba(0, 0, 0, 0.3); + &-add { + width: 15vw; + height: 15vw; + margin-left: 5vw; + margin-top: 5%; + background: linear-gradient(0deg, #A2A2A2, #A2A2A2), linear-gradient(180deg, #A2A2A2 0%, #d3d3d3 99.99%); + box-shadow: 0px 0.986257px 7.39693px rgba(0, 0, 0, 0.3); + } + } + } + &-content { + &-container { + width: 100vw; + position: fixed; + top: 0; + left: 0; + } + } + &-input { + font-size: 100%; + width: 100%; + border: none; + outline: none; + box-shadow: none; + color: #A2A2A2; + margin: 0; + padding: 0; + max-width: 1000px; + overflow-y: auto; + } + &-container { + padding-left: 2rem; + padding-right: 2rem; + width: 100vw; + max-width: 1000px; + } + &-subtitle { + text-align: left; + font-family: 'Mukta', sans-serif; + font-weight: 500; + font-size: 2rem; + height: 40px; + display: flex; + justify-content: center; + align-items: center; + } + &-title { + font-size: 3rem; + text-align: left; + font-family: 'Mukta', sans-serif; + font-weight: 600; + max-width: 1000px; + } + &-comment { + &-container { + width: 100vw; + max-width: 1000px; + } + } +} + +#comment { + display: none; + flex-direction: column; + box-sizing: border-box; + flex-direction: column; + place-content: center; + align-items: center; +} + +#comment-box { + display: none; + flex-direction: row; + box-sizing: border-box; + flex-direction: column; + place-content: center space-between; + align-items: center; + height: 5vh;background: #ffffff; + padding-left: 2rem; + padding-right: 2rem; + box-shadow: 0px -1px 50px rgba(0, 0, 0, 0.25); + position: fixed; + bottom: 0; + width: 100%; + left: 0; +} + +#comment-tab { + display: none; + flex-direction: row; + box-sizing: border-box; + flex-direction: column; + place-content: center space-between; + align-items: center; + height: 5vh; + background: #ffffff; + padding-left: 2rem; + padding-right: 2rem; + box-shadow: 0px -1px 50px rgba(0, 0, 0, 0.25); + position: fixed; + width: 100%; + top: 0; + left: 0; +} + +p.marked span.markdown p { + color: #333333 !important; +} + +p { + color:#A2A2A2; +} diff --git a/src/app/home/home.component.spec.ts b/src/app/home/home.component.spec.ts --- a/src/app/home/home.component.spec.ts +++ b/src/app/home/home.component.spec.ts @@ -3,7 +3,8 @@ import { ComponentFixture, ComponentFixtureAutoDetect, TestBed, async } from '@angular/core/testing'; import { DebugElement } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { MatCardModule, MatIconModule, MatListModule, MatMenuModule, MatSlideToggleModule, MatDialogRef, MatDialog, MatProgressSpinnerModule, MatSnackBarModule } from '@angular/material'; +import { MatCardModule, MatIconModule, MatListModule, MatMenuModule, MatSlideToggleModule, MatDialogRef, + MatDialog, MatProgressSpinnerModule, MatSnackBarModule } from '@angular/material'; import { Router, RouterModule } from '@angular/router'; import { ActivatedRoute } from '@angular/router'; import { Observable } from 'rxjs'; @@ -115,7 +116,8 @@ { provide: RouteService, useValue: routeServiceStub }, { provide: ComponentFixtureAutoDetect, useValue: true } ], - imports: [ MatCardModule, MatIconModule, MatListModule, MatMenuModule, FormsModule, ClipboardModule, MatProgressSpinnerModule, MatSlideToggleModule, RouterModule, MatSnackBarModule ] + imports: [ MatCardModule, MatIconModule, MatListModule, MatMenuModule, FormsModule, + ClipboardModule, MatProgressSpinnerModule, MatSlideToggleModule, RouterModule, MatSnackBarModule ] }); fixture = TestBed.createComponent(HomeComponent); comp = fixture.componentInstance; diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts --- a/src/app/home/home.component.ts +++ b/src/app/home/home.component.ts @@ -1,4 +1,5 @@ import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core'; +import { FormGroup, FormControl } from '@angular/forms'; import { MatDialog, MatSnackBar } from '@angular/material'; import { Router } from '@angular/router'; import { Subject } from 'rxjs/Subject'; @@ -13,6 +14,7 @@ import { Link } from '../_models/link'; import { Post } from '../_models/post'; import { Reputation } from '../_models/reputation'; +import { AreaService } from '../_services/area.service'; import { CommentService } from '../_services/comment.service'; import { FlagService } from '../_services/flag.service'; import { NavBarService } from '../_services/navBar.service'; @@ -27,15 +29,19 @@ @Component({ templateUrl: 'home.component.html', + styleUrls: ['./home.component.scss'] }) export class HomeComponent implements OnInit, OnDestroy { private systemAuthor: Author = new Author(375, 'WildFyre', '', '', false); areaCheck: string; blockedUsers: string[]; blanketText = `

Fyre Blanket

`; + areas = new Array(new Area('', '', 0, 0)); commentCount = 0; + commentForm: FormGroup; componentDestroyed: Subject = new Subject(); - currentArea: string; + currentArea: Area; + errors: any; fakePost: Post = new Post(0, this.systemAuthor, false, false, Date(), false, 'No more posts in this area, try creating one?', null, null, []); isCopied = false; @@ -43,7 +49,7 @@ loggedIn = true; post: Post = this.fakePost; rep: Reputation; - userID: number; + self: Author; wait = true; constructor( @@ -51,6 +57,7 @@ private dialog: MatDialog, private router: Router, private snackBar: MatSnackBar, + private areaService: AreaService, private commentService: CommentService, private flagService: FlagService, private navBarService: NavBarService, @@ -68,6 +75,11 @@ this.blockedUsers.pop(); } + this.commentForm = new FormGroup({ + 'comment': new FormControl(''), + 'image': new FormControl('') + }); + this.routeService.resetRoutes(); this.navBarService.comment @@ -77,7 +89,7 @@ if (!this.wait) { if (comment.comment !== '' && this.runImageCheck(comment.comment)) { if (comment.image) { - this.postService.setPicture(comment.image, this.post, this.currentArea, false, comment.comment) + this.postService.setPicture(comment.image, this.post, this.currentArea.name, false, comment.comment) .takeUntil(this.componentDestroyed) .subscribe(result2 => { if (!result2.getError()) { @@ -90,7 +102,7 @@ } }); } else { - this.postService.comment(this.currentArea, this.post, comment.comment) + this.postService.comment(this.currentArea.name, this.post, comment.comment) .takeUntil(this.componentDestroyed) .subscribe(); this.navBarService.clearInputs.next(true); @@ -109,10 +121,33 @@ this.wait = false; }); + this.areaService.getAreas() + .takeUntil(this.componentDestroyed) + .subscribe(areas => { + this.areas = []; + + for (let i = 0; i < areas.length; i++) { + this.areaService.getAreaRep(areas[i].name) + .takeUntil(this.componentDestroyed) + .subscribe(result => { + let area; + area = new Area( + areas[i].name, + areas[i].displayname, + result.reputation, + result.spread + ); + + this.areas.push(area); + this.cdRef.detectChanges(); + }); + } + }); + this.profileService.getSelf() .takeUntil(this.componentDestroyed) .subscribe( (author: Author) => { - this.userID = author.user; + this.self = author; this.loggedIn = true; }); this.refresh(true); @@ -188,6 +223,16 @@ return this.blockedUsers.includes(String(c)); } + hideViews() { + document.getElementById('post').style.display = 'none'; + document.getElementById('home').style.display = 'none'; + document.getElementById('comment').style.display = 'none'; + document.getElementById('comment-box').style.display = 'none'; + document.getElementById('comment-tab').style.display = 'none'; + this.errors = null; + this.loading = false; + } + openCommentDeleteDialog(c: Comment) { const dialogRef = this.dialog.open(ConfirmDeletionDialogComponent); dialogRef.afterClosed() @@ -195,7 +240,7 @@ .subscribe(result => { if (result.bool) { this.commentService.deleteComment( - this.currentArea, + this.currentArea.name, this.post, c ); @@ -221,6 +266,12 @@ }); } + postComment() { + this.loading = true; + this.navBarService.comment.next(new CommentData(this.commentForm.controls.comment.value, this.commentForm.controls.image.value)); + this.loading = false; + } + refresh(reload: boolean) { this.wait = true; this.loading = true; @@ -228,7 +279,7 @@ .takeUntil(this.componentDestroyed) .subscribe((currentArea: Area) => { if (currentArea.name !== '') { - this.currentArea = currentArea.name; + this.currentArea = currentArea; if ((reload === true || this.areaCheck !== currentArea.name) && currentArea.name !== '') { this.postService.getNextPost(currentArea.name) @@ -238,7 +289,7 @@ this.post = nextPost; this.commentCount = this.post.comments.length; this.loading = false; - this.areaCheck = this.currentArea; + this.areaCheck = this.currentArea.name; this.navBarService.hasPost.next(true); this.cdRef.detectChanges(); } else { @@ -247,20 +298,20 @@ this.post = this.fakePost; this.commentCount = 0; this.loading = false; - this.areaCheck = this.currentArea; + this.areaCheck = this.currentArea.name; this.navBarService.hasPost.next(false); this.cdRef.detectChanges(); } }); } else if (currentArea.name === '') { } else { - this.postService.getPost(this.currentArea, this.post.id, false) + this.postService.getPost(this.currentArea.name, this.post.id, false) .takeUntil(this.componentDestroyed) .subscribe(post => { this.post = post; this.commentCount = this.post.comments.length; this.loading = false; - this.areaCheck = this.currentArea; + this.areaCheck = this.currentArea.name; this.navBarService.hasPost.next(true); this.cdRef.detectChanges(); }); @@ -318,12 +369,12 @@ this.navBarService.clearInputs.next(true); this.cdRef.detectChanges(); this.postService.spread( - this.currentArea, + this.currentArea.name, this.post, spread ); - this.postService.getNextPost(this.currentArea) + this.postService.getNextPost(this.currentArea.name) .subscribe(nextPost => { if (nextPost) { this.post = nextPost; @@ -340,8 +391,37 @@ } subscribe(s: boolean) { - this.postService.subscribe(this.currentArea, this.post, s) + this.postService.subscribe(this.currentArea.name, this.post, s) .takeUntil(this.componentDestroyed) .subscribe(); } + + switchRoute(s: string) { + if (s === 'home') { + this.router.navigateByUrl('/'); + } else if (s === 'profile') { + this.router.navigateByUrl('/profile'); + } else if (s === 'notifications') { + this.router.navigateByUrl('/notifications'); + } else if (s === 'my-posts') { + this.router.navigateByUrl('/posts'); + } + } + + switchView(s: string, a?: Area) { + if (s === 'home') { + this.hideViews(); + document.getElementById('home').style.display = 'flex'; + document.getElementById('post').style.display = 'block'; + } else if (s === 'comment') { + this.hideViews(); + document.getElementById('comment').style.display = 'flex'; + document.getElementById('comment-box').style.display = 'flex'; + document.getElementById('comment-tab').style.display = 'flex'; + } else if (s === 'areaList') { + this.hideViews(); + document.getElementById('areaList').style.display = 'flex'; + document.getElementById('navBar').style.display = 'flex'; + } + } } diff --git a/src/app/login/login.component.html b/src/app/login/login.component.html --- a/src/app/login/login.component.html +++ b/src/app/login/login.component.html @@ -1,37 +1,390 @@ - + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
diff --git a/src/app/login/login.component.scss b/src/app/login/login.component.scss new file mode 100644 --- /dev/null +++ b/src/app/login/login.component.scss @@ -0,0 +1,65 @@ +.login { + &-button { + width: 100%; + font-family: 'Mukta', sans-serif; + border: 1px solid #EA6C40; + border-radius: 4px; + font-weight: 700; + } + &-container { + padding-left: 2rem; + padding-right: 2rem; + width: 100vw; + height: 100vh; + max-width: 1000px; + } + &-input { + width: 100%; + border: none; + outline: none; + box-shadow: none; + color: #A2A2A2; + } + &-subtitle { + text-align: left; + font-family: 'Mukta', sans-serif; + color: #A2A2A2; + font-weight: 400; + } + &-title { + font-size: 6rem; + text-align: left; + font-family: 'Mukta', sans-serif; + font-weight: 900; + } +} + +#login { + display: none; + flex-direction: column; + box-sizing: border-box; +} + +#register { + display: none; + flex-direction: column; + box-sizing: border-box; +} + +#recover-username { + display: none; + flex-direction: column; + box-sizing: border-box; +} + +#recover-password { + display: none; + flex-direction: column; + box-sizing: border-box; +} + +#recover-password2 { + display: none; + flex-direction: column; + box-sizing: border-box; +} diff --git a/src/app/login/login.component.spec.ts b/src/app/login/login.component.spec.ts --- a/src/app/login/login.component.spec.ts +++ b/src/app/login/login.component.spec.ts @@ -46,9 +46,9 @@ return Observable.of( new SuperNotification(1, '', '', new Array( - new Notification('', - new NotificationPost(0, - new Author(0, '', '', '', false), 'test'), + new Notification('', + new NotificationPost(0, + new Author(0, '', '', '', false), 'test'), new Array(0))) )); } diff --git a/src/app/login/login.component.ts b/src/app/login/login.component.ts --- a/src/app/login/login.component.ts +++ b/src/app/login/login.component.ts @@ -1,22 +1,34 @@ -import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core'; +import { FormControl, FormGroup } from '@angular/forms'; import { MatSnackBar } from '@angular/material'; import { Router } from '@angular/router'; import 'rxjs/add/operator/catch'; import { Subject } from 'rxjs/Subject'; -import { AuthError } from '../_models/auth'; import { AuthenticationService } from '../_services/authentication.service'; import { NavBarService } from '../_services/navBar.service'; import { NotificationService } from '../_services/notification.service'; +import { RegistrationService } from '../_services/registration.service'; import { RouteService } from '../_services/route.service'; +import { ReCaptchaComponent } from 'angular2-recaptcha'; @Component({ - templateUrl: 'login.component.html' + templateUrl: 'login.component.html', + styleUrls: ['./login.component.scss'] }) export class LoginComponent implements OnInit, OnDestroy { + @ViewChild(ReCaptchaComponent) captcha: ReCaptchaComponent; + componentDestroyed: Subject = new Subject(); - errors: string; + errors: any; loading = false; - model: any = {}; + loginForm: FormGroup; + registerForm: FormGroup; + recoverUsernameForm: FormGroup; + recoverPasswordForm: FormGroup; + recoverPasswordForm2: FormGroup; + resetTransaction: string; + token: any; + submitted = false; constructor( private router: Router, @@ -24,14 +36,38 @@ private authenticationService: AuthenticationService, private navBarService: NavBarService, private notificationService: NotificationService, + private registrationService: RegistrationService, private routeService: RouteService - ) { - const snackBarRef = this.snackBar.open('Authentication Required', 'Close', { - duration: 3000 - }); - } + ) { } ngOnInit() { + this.loginForm = new FormGroup({ + 'usernamel': new FormControl(''), + 'passwordl': new FormControl(''), + }); + + this.registerForm = new FormGroup({ + 'usernamer': new FormControl(''), + 'emailr': new FormControl(''), + 'passwordr': new FormControl(''), + 'password2r': new FormControl(''), + }); + + this.recoverUsernameForm = new FormGroup({ + 'emailru': new FormControl(''), + }); + + this.recoverPasswordForm = new FormGroup({ + 'emailrp': new FormControl(''), + 'usernamerp': new FormControl(''), + }); + + this.recoverPasswordForm2 = new FormGroup({ + 'tokenrp2': new FormControl(''), + 'passwordrp2': new FormControl(''), + 'password2rp2': new FormControl(''), + }); + // reset login status this.routeService.resetRoutes(); this.authenticationService.logout(); @@ -44,25 +80,217 @@ this.componentDestroyed.complete(); } + switchView(s: string) { + if (s === 'register') { + this.hideViews(); + document.getElementById('register').style.display = 'flex'; + } else if (s === 'login') { + this.hideViews(); + document.getElementById('login').style.display = 'flex'; + } else if (s === 'landing') { + this.hideViews(); + document.getElementById('landing').style.display = 'flex'; + } else if (s === 'recover-password') { + this.hideViews(); + document.getElementById('recover-password').style.display = 'flex'; + } else if (s === 'recover-password2') { + this.hideViews(); + document.getElementById('recover-password2').style.display = 'flex'; + } else if (s === 'recover-username') { + this.hideViews(); + document.getElementById('recover-username').style.display = 'flex'; + } + } + + hideViews() { + document.getElementById('register').style.display = 'none'; + document.getElementById('login').style.display = 'none'; + document.getElementById('landing').style.display = 'none'; + document.getElementById('recover-password').style.display = 'none'; + document.getElementById('recover-password2').style.display = 'none'; + document.getElementById('recover-username').style.display = 'none'; + this.errors = null; + this.loading = false; + this.submitted = false; + } + login() { + this.errors = null; + this.loading = true; + this.submitted = false; + + if (this.loginForm.valid) { + this.authenticationService.login(this.loginForm.controls.usernamel.value, this.loginForm.controls.passwordl.value) + .takeUntil(this.componentDestroyed) + .subscribe(result => { + if (!result.getError()) { + this.notificationService.getSuperNotification(10, 0) + .takeUntil(this.componentDestroyed) + .subscribe(superNotification => { + this.navBarService.notifications.next(superNotification.count); + }); + this.navBarService.loggedIn.next(true); + this.navBarService.areaVisible.next(true); + this.router.navigate(['/']); + this.loading = false; + this.submitted = true; + } else { + this.errors = result.getError(); + this.loading = false; + this.submitted = true; + } + }); + } else { + this.loading = false; + this.submitted = true; + this.snackBar.open('Your information is incorrect', 'Close', { + duration: 3000 + }); + } + } + + recoverPassword() { + this.errors = null; + this.loading = true; + this.submitted = false; + if (this.recoverPasswordForm.valid) { + this.registrationService.recoverPasswordStep1( + this.recoverPasswordForm.controls.emailrp.value, + this.recoverPasswordForm.controls.usernamerp.value, + this.token) + .takeUntil(this.componentDestroyed) + .subscribe(result => { + if (!result.getError()) { + this.router.navigateByUrl('/recover/password/' + result.transaction); + this.resetTransaction = result.transaction; + this.loading = false; + this.submitted = true; + } else { + this.errors = result.getError(); + this.loading = false; + this.submitted = true; + } + }); + } else { + this.loading = false; + this.submitted = true; + this.snackBar.open('Your information is incorrect', 'Close', { + duration: 3000 + }); + } + } + + recoverUsername() { + this.errors = null; this.loading = true; - this.authenticationService.login(this.model.username, this.model.password) + this.submitted = false; + + if (this.recoverUsernameForm.valid) { + this.registrationService.recoverUsername(this.recoverUsernameForm.controls.emailru.value, this.token) .takeUntil(this.componentDestroyed) .subscribe(result => { if (!result.getError()) { - this.notificationService.getSuperNotification(10, 0) - .takeUntil(this.componentDestroyed) - .subscribe(superNotification => { - this.navBarService.notifications.next(superNotification.count); + this.snackBar.open('We will contact you via the information provided', 'Close', { + duration: 3000 }); - this.navBarService.loggedIn.next(true); - this.navBarService.areaVisible.next(true); - this.router.navigate(['/']); this.loading = false; + this.submitted = true; + } else { + this.errors = result.getError(); + this.loading = false; + this.submitted = true; } - }, err => { - this.errors = 'Unable to log in with provided credentials.'; + }); + } else { this.loading = false; - }); + this.submitted = true; + this.snackBar.open('Your information is incorrect', 'Close', { + duration: 3000 + }); + } + } + + register() { + this.errors = null; + this.loading = true; + this.submitted = false; + + if (this.registerForm.valid) { + if (this.registerForm.controls.passwordr.value === this.registerForm.controls.password2r.value) { + this.registrationService.register( + this.registerForm.controls.usernamer.value, + this.registerForm.controls.emailr.value, + this.registerForm.controls.passwordr.value, + this.token) + .takeUntil(this.componentDestroyed) + .subscribe(result => { + if (!result.getError()) { + this.router.navigate(['/register/success']); + this.loading = false; + this.submitted = true; + } else { + this.errors = result.getError(); + this.loading = false; + this.submitted = true; + } + }); + } else { + this.loading = false; + this.submitted = true; + this.snackBar.open('Your passwords do not match', 'Close', { + duration: 3000 + }); + } + } else { + this.loading = false; + this.submitted = true; + this.snackBar.open('Your information is incorrect', 'Close', { + duration: 3000 + }); + } + } + + resetPassword() { + if (this.recoverPasswordForm2.valid) { + if (this.recoverPasswordForm2.controls.passwordrp2.value === this.recoverPasswordForm2.controls.password2rp2.value) { + this.registrationService.recoverPasswordStep2( + this.recoverPasswordForm2.controls.passwordrp2.value, + this.recoverPasswordForm2.controls.tokenrp2.value, + this.resetTransaction, + this.token) + .takeUntil(this.componentDestroyed) + .subscribe(result => { + if (!result.getError()) { + this.snackBar.open('Your new password is now set', 'Close', { + duration: 3000 + }); + this.router.navigateByUrl('login'); + this.loading = false; + this.captcha.reset(); + } else { + this.snackBar.open('You inputted something incorrectly', 'Close', { + duration: 3000 + }); + this.errors = result.getError(); + this.loading = false; + this.captcha.reset(); + } + }); + } else { + this.snackBar.open('Your passwords did not match', 'Close', { + duration: 3000 + }); + } + } else { + this.loading = false; + this.submitted = true; + this.snackBar.open('Your information is incorrect', 'Close', { + duration: 3000 + }); + } + } + + setCaptchaResponse(res: any) { + this.token = res; } } diff --git a/src/app/navBar/navBar.component.html b/src/app/navBar/navBar.component.html --- a/src/app/navBar/navBar.component.html +++ b/src/app/navBar/navBar.component.html @@ -1,90 +1,23 @@ - - - - - - -
- - - - - - - - - - - - - - - - - - About Us - - - Open Source! - - - FAQ - - - Terms and Conditions - - - Privacy Policy - - - Logout - -
- - - -
- WildFyre Facebook - WildFyre Telegram - WildFyre Twitter -
-
- - Please report any and all bugs to bugs@wildfyre.net - -
-
- Copyright © 2017-2019 WildFyre -
-
-
-


-
+ + + diff --git a/src/app/navBar/navBar.component.scss b/src/app/navBar/navBar.component.scss new file mode 100644 --- /dev/null +++ b/src/app/navBar/navBar.component.scss @@ -0,0 +1,7 @@ +.white { + color: #ffffff; +} + +p { + color:#A2A2A2; +} diff --git a/src/app/navBar/navBar.component.spec.ts b/src/app/navBar/navBar.component.spec.ts --- a/src/app/navBar/navBar.component.spec.ts +++ b/src/app/navBar/navBar.component.spec.ts @@ -6,7 +6,8 @@ import { FormsModule } from '@angular/forms'; import { ComponentFixture, ComponentFixtureAutoDetect, TestBed , async} from '@angular/core/testing'; import { Router, ActivatedRoute, RouterModule, Routes } from '@angular/router'; -import { MatTabsModule, MatListModule, MatMenuModule, MatDialogModule, MatSelectModule, MatSidenavModule, MatOptionModule, MatSnackBarModule } from '@angular/material'; +import { MatTabsModule, MatListModule, MatMenuModule, MatDialogModule, MatSelectModule, + MatSidenavModule, MatOptionModule, MatSnackBarModule } from '@angular/material'; import { Observable } from 'rxjs'; import { Author } from '../_models/author'; import { Notification } from '../_models/notification'; @@ -82,7 +83,8 @@ { provide: NotificationService, useValue: notificationServiceStub }, { provide: ComponentFixtureAutoDetect, useValue: true } ], - imports: [ MatTabsModule, MatListModule, MatOptionModule, FormsModule, MatSelectModule, MatSidenavModule, MatMenuModule, MatSnackBarModule, MatDialogModule, RouterModule.forRoot(routes), BrowserAnimationsModule ], + imports: [ MatTabsModule, MatListModule, MatOptionModule, FormsModule, MatSelectModule, + MatSidenavModule, MatMenuModule, MatSnackBarModule, MatDialogModule, RouterModule.forRoot(routes), BrowserAnimationsModule ], }); fixture = TestBed.createComponent(NavBarComponent); comp = fixture.componentInstance; diff --git a/src/app/navBar/navBar.component.ts b/src/app/navBar/navBar.component.ts --- a/src/app/navBar/navBar.component.ts +++ b/src/app/navBar/navBar.component.ts @@ -15,12 +15,13 @@ @Component({ selector: 'app-nav-bar', - templateUrl: 'navBar.component.html' + templateUrl: 'navBar.component.html', + styleUrls: ['./navBar.component.scss'] }) export class NavBarComponent implements OnInit, OnDestroy { @ViewChild('sidenav') sidenav: MatSidenav; - activeLinkIndex = 2; + activeLinkIndex = 1; areas = new Array(new Area('', '', 0, 0)); areaReputation: { [area: string]: number; } = { }; areaSpread: { [area: string]: number; } = { }; @@ -58,52 +59,14 @@ private authenticationService: AuthenticationService, private notificationService: NotificationService, private navBarService: NavBarService - ) { - this.routeLinks = [ - {label: 'Profile', link: '/profile/', index: '0'}, - {label: 'Notifications', link: '/notifications/1/', index: '1'}, - {label: 'Home', link: '/', index: '2'}, - {label: 'My Posts', link: '/posts/1/', index: '3'}, - {label: 'Create a Post', link: '/create/', index: '4'} - ]; - - this.mobileRouteLinks = [ - {label: 'perm_identity', link: '/profile/', index: '0'}, - {label: 'notifications_none', link: '/notifications/1/', index: '1'}, - {label: 'home', link: '/', index: '2'}, - {label: 'content_copy', link: '/posts/1/', index: '3'}, - {label: 'create', link: '/create/', index: '4'} - ]; - } + ) { } ngOnInit() { - this.navBarService.areaVisible - .takeUntil(this.componentDestroyed) - .subscribe((visible: boolean) => { - this.areaVisible = visible; - this.cdRef.detectChanges(); - }); - - this.navBarService.hasPost - .takeUntil(this.componentDestroyed) - .subscribe((has: boolean) => { - this.hasPost = has; - this.cdRef.detectChanges(); - }); - - this.navBarService.clearInputs + this.router.events .takeUntil(this.componentDestroyed) - .subscribe((action: boolean) => { - if (action) { - this.comment.comment = ''; - this.comment.image = null; - this.contractBox(); - this.commentDisabled = false; - } else { - this.commentDisabled = false; - } + .subscribe((url: any) => { + this.setActiveIndex(url.url); }); - this.navBarService.loggedIn .takeUntil(this.componentDestroyed) .subscribe((loggedIn: boolean) => { @@ -127,100 +90,11 @@ } ngOnDestroy() { - this.contractBox(); this.cdRef.detach(); this.componentDestroyed.next(true); this.componentDestroyed.complete(); } - private addLineBreak(s: string) { - if (this.comment.comment !== '') { - this.comment.comment += '\n'; - } - this.comment.comment += s; - } - - addBlockQoutes() { - this.addLineBreak('> Blockquote example'); - } - - addBold() { - this.addLineBreak('**Example**'); - } - - addImage() { - const dialogRef = this.dialog.open(PictureDialogComponent); - dialogRef.componentInstance.comment = true; - dialogRef.afterClosed() - .takeUntil(this.componentDestroyed) - .subscribe(result => { - if (result.bool) { - this.comment.image = result.picture; - this.snackBar.open('Image added successfully', 'Close', { - duration: 3000 - }); - } else { - this.snackBar.open('You did not select a valid image file', 'Close', { - duration: 3000 - }); - } - }); - } - - addItalics() { - this.addLineBreak('_Example_'); - } - - addStrikethrough() { - this.addLineBreak('~~Example~~'); - } - - close() { - this.sidenav.close(); - } - - contractBox() { - this.expanded = false; - this.rowsExapanded = 2; - this.styleMobile = ''; - - this.styleHeightTextarea = '56px'; - - if (window.screen.width < 600) { - this.styleHeightTextarea = '40px'; - this.styleBottomTextarea = '40px'; - this.styleBottomEditor = '3px'; - this.styleHeightEditor = '48px'; - this.styleBottomSend = '42px'; - this.styleHeightSend = '38px'; - } - } - - deleteImage() { - this.comment.image = null; - this.snackBar.open('Image removed successfully', 'Close', { - duration: 3000 - }); - } - - expandBox() { - this.expanded = true; - this.rowsExapanded = 3; - this.styleMobile = 'none'; - - this.styleBottomEditor = '48px'; - this.styleHeightTextarea = '96px'; - - if (window.screen.width < 600) { - this.styleHeightTextarea = '118px'; - this.styleBottomTextarea = '0px'; - this.styleBottomEditor = '59px'; - this.styleHeightEditor = '59px'; - this.styleBottomSend = '0px'; - this.styleHeightSend = '59px'; - } - } - getNotificationLength(nLength: number) { if (nLength.toString().length === 4) { return nLength.toString().slice(0, 1) + 'K'; @@ -251,13 +125,6 @@ this.cdRef.detectChanges(); }); - this.navBarService.isVisibleSource - .takeUntil(this.componentDestroyed) - .subscribe((isVisible: string) => { - this.styleMobile = isVisible; - this.cdRef.detectChanges(); - }); - Observable.interval(2000 * 60) .takeUntil(this.componentDestroyed) .subscribe(x => { @@ -269,12 +136,6 @@ }); }); - this.router.events - .takeUntil(this.componentDestroyed) - .subscribe((url: any) => { - this.setActiveIndex(url.url); - }); - this.areaService.getAreas() .takeUntil(this.componentDestroyed) .subscribe(areas => { @@ -344,62 +205,48 @@ } if (s === '/profile') { this.stylePage = false; - this.activeLinkIndex = 0; - this.navBarService.areaVisible.next(false); + this.activeLinkIndex = 4; } else if (s === '/notifications/archive') { this.stylePage = false; - this.width = '90%'; - this.activeLinkIndex = 1; - this.navBarService.areaVisible.next(true); + this.activeLinkIndex = 2; } else if (s.lastIndexOf('/notifications/archive/') !== -1) { this.stylePage = false; - this.width = '90%'; - this.activeLinkIndex = 1; - this.navBarService.areaVisible.next(true); + this.activeLinkIndex = 2; } else if (s === '/notifications') { - this.stylePage = false; - this.activeLinkIndex = 1; - this.navBarService.areaVisible.next(false); + this.activeLinkIndex = 2; } else if (s.lastIndexOf('/notifications/') !== -1) { - this.stylePage = false; - this.activeLinkIndex = 1; - this.navBarService.areaVisible.next(false); - } else if (s === '/') { - this.stylePage = true; this.activeLinkIndex = 2; - this.navBarService.areaVisible.next(true); + } else if (s === '/') { + this.activeLinkIndex = 1; } else if (s === '/posts') { - this.stylePage = false; this.activeLinkIndex = 3; - this.navBarService.areaVisible.next(true); } else if (s.lastIndexOf('/posts/') !== -1) { - this.stylePage = false; this.activeLinkIndex = 3; - this.navBarService.areaVisible.next(true); } else if (s === '/create') { - this.stylePage = false; - this.activeLinkIndex = 4; - this.navBarService.areaVisible.next(true); + this.activeLinkIndex = -1; } else if (s.lastIndexOf('/create/') !== -1) { - this.stylePage = false; - this.activeLinkIndex = 4; - this.navBarService.areaVisible.next(false); + this.activeLinkIndex = -1; } else if (s === '/drafts') { - this.stylePage = false; - this.width = '90%'; - this.activeLinkIndex = 4; - this.navBarService.areaVisible.next(true); + this.activeLinkIndex = -1; } else if (s.lastIndexOf('/areas/') !== -1) { - this.stylePage = true; - this.width = '90%'; - this.activeLinkIndex = 2; - this.navBarService.areaVisible.next(false); + this.activeLinkIndex = -1; } else if (s.lastIndexOf('/user/') !== -1) { - this.stylePage = false; - this.width = '90%'; - this.activeLinkIndex = 0; - this.navBarService.areaVisible.next(false); + this.activeLinkIndex = -1; + } else if (s.lastIndexOf('/login') !== -1) { + this.activeLinkIndex = -1; } this.cdRef.detectChanges(); } + + switchRoute(s: string) { + if (s === 'home') { + this.router.navigateByUrl('/'); + } else if (s === 'profile') { + this.router.navigateByUrl('/profile'); + } else if (s === 'notifications') { + this.router.navigateByUrl('/notifications'); + } else if (s === 'my-posts') { + this.router.navigateByUrl('/posts'); + } + } } diff --git a/src/app/notification/notification.component.html b/src/app/notification/notification.component.html deleted file mode 100644 --- a/src/app/notification/notification.component.html +++ /dev/null @@ -1,25 +0,0 @@ - - -
- -
- -
- No more notifications, try engaging more? -
- -
- -
- -
-

{{notification.comments.length}}

-
-
- {{notification.post.text | slice:0:31}}… -
- –{{notification.post.author.name}} -
-
-
- diff --git a/src/app/notificationArchive/notificationArchive.component.html b/src/app/notificationArchive/notificationArchive.component.html deleted file mode 100644 --- a/src/app/notificationArchive/notificationArchive.component.html +++ /dev/null @@ -1,67 +0,0 @@ - - - No posts, try commenting on posts? - - -

- -
arrow_back
- - - - - - visibility_on - visibility_off - image - ... -
- {{post.created}} -
-
-
-
- - - - diff --git a/src/app/notificationArchive/notificationArchive.component.spec.ts b/src/app/notificationArchive/notificationArchive.component.spec.ts deleted file mode 100644 --- a/src/app/notificationArchive/notificationArchive.component.spec.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { By } from '@angular/platform-browser'; -import { ComponentFixture, ComponentFixtureAutoDetect, TestBed, async } from '@angular/core/testing'; -import { FormsModule } from '@angular/forms'; -import { NO_ERRORS_SCHEMA, Component } from '@angular/core'; -import { MatCardModule, MatTabsModule, MatProgressSpinnerModule, MatSlideToggleModule } from '@angular/material'; -import { Router, RouterModule, ActivatedRoute } from '@angular/router'; -import { Observable } from 'rxjs'; -import { Author } from '../_models/author'; -import { Comment } from '../_models/comment'; -import { Notification } from '../_models/notification'; -import { Post } from '../_models/post'; -import { SuperPost } from '../_models/superPost'; -import { MarkedPipe } from '../_pipes/marked.pipe'; -import { AreaService } from '../_services/area.service'; -import { AuthenticationService } from '../_services/authentication.service'; -import { NavBarService } from '../_services/navBar.service'; -import { NotificationService } from '../_services/notification.service'; -import { RouteService } from '../_services/route.service'; -import { NotificationArchiveComponent } from './notificationArchive.component'; -import { NgxMasonryModule } from '../_modules/ngx-masonry/ngx-masonry.module'; -import { NgxPaginationModule } from 'ngx-pagination'; - -describe('NotificationArchiveComponent', () => { - let comp: NotificationArchiveComponent; - let fixture: ComponentFixture; - - beforeEach(() => { - const routerStub = { - url: '/notifications' - }; - const authenticationServiceStub = { - token: 'token' - }; - const areaServiceStub = { - isAreaChecked: {}, - currentAreaName: {}, - getAreaRep: () => ({ - subscribe: () => ({}) - }) - }; - const activatedRouteStub = { - params: Observable.of({'id': 1}) - }; - const navBarServiceStub = {}; - const routeServiceStub = {}; - - const notificationServiceStub = { - getArchive: () => { - return Observable.of( - new SuperPost(1, '', '', - new Array( - new Post(1, - new Author(1, 'test', null, 'test', false), false, false, '2017-07-22T12:03:23.465373Z', false, 'test', null, [], - new Array( - new Comment(1, - new Author(1, 'test', null, 'test', false), '2017-07-22T12:03:23.465373Z', 'test', null))) - ))); - } - }; - - TestBed.configureTestingModule({ - declarations: [ NotificationArchiveComponent, MarkedPipe ], - providers: [ - { provide: Router, useValue: routerStub }, - { provide: ActivatedRoute, useValue: activatedRouteStub }, - { provide: AreaService, useValue: areaServiceStub }, - { provide: AuthenticationService, useValue: authenticationServiceStub }, - { provide: NavBarService, useValue: navBarServiceStub }, - { provide: NotificationService, useValue: notificationServiceStub }, - { provide: RouteService, useValue: routeServiceStub }, - { provide: ComponentFixtureAutoDetect, useValue: true } - ], - imports: [ MatCardModule, RouterModule, MatTabsModule, MatProgressSpinnerModule, MatSlideToggleModule, FormsModule, NgxMasonryModule, NgxPaginationModule ], - }).compileComponents(); - fixture = TestBed.createComponent(NotificationArchiveComponent); - comp = fixture.componentInstance; - }); - - it('should set notification text', async(() => { - fixture.detectChanges(); - - fixture.whenStable().then(() => { - fixture.detectChanges(); - expect(fixture.debugElement.query(By.css('.notifications')).nativeElement.textContent).toBe('test'); - }); - })); -}); diff --git a/src/app/postView/postView.component.html b/src/app/postView/postView.component.html deleted file mode 100644 --- a/src/app/postView/postView.component.html +++ /dev/null @@ -1,112 +0,0 @@ - -
- -
arrow_back
- - -
- Avatar of {{post?.author?.name}} - Avatar of {{post?.author?.name}} - -
- {{post?.author?.name}}

{{post?.created}}

-
-
-
- -
-
{{getCommentLength(post?.comments?.length)}}
- - - - - - - -
-
-
- -
arrow_back
- - - -
- Avatar of {{post?.author?.name}} - Avatar of {{post?.author?.name}} - -
- {{post?.author?.name}}

{{post?.created}}

-
-
-
- -
-
{{getCommentLength(post?.comments?.length)}}
- - - - - - - - - - -
-
-
- - -
- -
- - - - -
-
- -
- Avatar of {{comment.author?.name}} - Avatar of {{comment.author?.name}} - -
- {{comment.author?.name}}

{{comment.created}}

-
-
-
-
- - -
- - - - - - - -
-
- - -
- Avatar of {{comment.author?.name}} - Avatar of {{comment.author?.name}} - -
- {{comment.author?.name}}

{{comment.created}}

-
-
-
-
- -
-
- - - No comments, try commenting? - - diff --git a/src/app/postView/postView.component.spec.ts b/src/app/postView/postView.component.spec.ts deleted file mode 100644 --- a/src/app/postView/postView.component.spec.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { By } from '@angular/platform-browser'; -import { ComponentFixture, TestBed, async } from '@angular/core/testing'; -import { DebugElement } from '@angular/core'; -import { MatIconModule, MatListModule, MatSnackBar, MatMenuModule, MatProgressSpinnerModule, MatCardModule, MatDialogModule, MatSnackBarModule } from '@angular/material'; -import { FormsModule } from '@angular/forms'; -import { Router } from '@angular/router'; -import { RouterTestingModule } from '@angular/router/testing'; -import { Observable } from 'rxjs'; -import { ActivatedRoute } from '@angular/router'; -import { Author } from '../_models/author'; -import { Comment } from '../_models/comment'; -import { Post } from '../_models/post'; -import { MarkedPipe } from '../_pipes/marked.pipe'; -import { AreaService } from '../_services/area.service'; -import { AuthenticationService } from '../_services/authentication.service'; -import { CommentService } from '../_services/comment.service'; -import { FlagService } from '../_services/flag.service'; -import { NavBarService } from '../_services/navBar.service'; -import { PostService } from '../_services/post.service'; -import { ProfileService } from '../_services/profile.service'; -import { RouteService } from '../_services/route.service'; -import { PostViewComponent } from './postView.component'; -import { ClipboardModule } from 'ngx-clipboard'; - -describe('PostViewComponent', () => { - let comp: PostViewComponent; - let fixture: ComponentFixture; - let de: DebugElement; - let el: HTMLElement; - - beforeEach(() => { - const routerStub = { - url: '/areas/fun/78270840618' - }; - const activatedRouteStub = { - params: Observable.of({'id': 1}) - }; - const postStub = {}; - const commentStub = {}; - const areaServiceStub = { - isAreaChecked: {}, - currentAreaName: {} - }; - const authenticationServiceStub = { - token: 'token' - }; - const commentServiceStub = { - deleteComment: () => ({}) - }; - const flagServiceStub = { - currentComment: {}, - currentPost: {}, - openDialog: () => ({}) - }; - const postServiceStub = { - getPost: () => { - return Observable.of( - new Array( - new Post(1, - new Author(1, 'test', null, 'test', false), false, false, '2017-07-22T12:03:23.465373Z', false, 'test', null, [], - new Array( - new Comment(1, - new Author(1, 'test', null, 'test', false), '2017-07-22T12:03:23.465373Z', 'test', null))) - ) - ); - }, - comment: () => ({ - subscribe: () => ({}) - }), - subscribe: () => ({ - subscribe: () => ({}) - }), - deletePost: () => ({}) - }; - const profileServiceStub = { - getSelf: () => { - return Observable.of( - new Author(1, 'Test User', null, 'test', false) - ); - } - }; - const routeServiceStub = {}; - const navBarServiceStub = {}; - TestBed.configureTestingModule({ - declarations: [ PostViewComponent, MarkedPipe ], - providers: [ - { provide: Router, useValue: routerStub }, - { provide: ActivatedRoute, useValue: activatedRouteStub }, - { provide: Post, useValue: postStub }, - { provide: Comment, useValue: commentStub }, - { provide: AreaService, useValue: areaServiceStub }, - { provide: AuthenticationService, useValue: authenticationServiceStub }, - { provide: CommentService, useValue: commentServiceStub }, - { provide: FlagService, useValue: flagServiceStub }, - { provide: NavBarService, useValue: navBarServiceStub }, - { provide: PostService, useValue: postServiceStub }, - { provide: ProfileService, useValue: profileServiceStub }, - { provide: RouteService, useValue: routeServiceStub } - ], - imports: [ MatListModule, MatMenuModule, MatCardModule, ClipboardModule, MatDialogModule, MatIconModule, MatProgressSpinnerModule, MatSnackBarModule, - FormsModule, BrowserAnimationsModule, RouterTestingModule ], - }); - fixture = TestBed.createComponent(PostViewComponent); - comp = fixture.componentInstance; - de = fixture.debugElement.query(By.css('.mainText')); - el = de.nativeElement; - }); - - it('should set post text', async(() => { - fixture.detectChanges(); - - fixture.whenStable().then(() => { - fixture.detectChanges(); - expect(el.textContent).toBe('test\n'); - }); - })); - - it('should set comment text', async(() => { - fixture.detectChanges(); - - fixture.whenStable().then(() => { - fixture.detectChanges(); - expect(fixture.debugElement.query(By.css('.commentText')).nativeElement.textContent).toBe('test\n'); - }); - })); - -}); diff --git a/src/app/postView/postView.component.ts b/src/app/postView/postView.component.ts deleted file mode 100644 --- a/src/app/postView/postView.component.ts +++ /dev/null @@ -1,322 +0,0 @@ -import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core'; -import { MatDialog, MatSnackBar } from '@angular/material'; -import { Router, ActivatedRoute } from '@angular/router'; -import { Subject } from 'rxjs/Subject'; -import { ConfirmDeletionDialogComponent } from '../_dialogs/confirmDeletion.dialog.component'; -import { FlagDialogComponent } from '../_dialogs/flag.dialog.component'; -import { ShareDialogComponent } from '../_dialogs/share.dialog.component'; -import { Author } from '../_models/author'; -import { Comment } from '../_models/comment'; -import { CommentData } from '../_models/commentData'; -import * as C from '../_models/constants'; -import { Link } from '../_models/link'; -import { Post } from '../_models/post'; -import { CommentService } from '../_services/comment.service'; -import { FlagService } from '../_services/flag.service'; -import { NavBarService } from '../_services/navBar.service'; -import { PostService } from '../_services/post.service'; -import { ProfileService } from '../_services/profile.service'; -import { RouteService } from '../_services/route.service'; - -enum TypeOfReport { - Post, - Comment -} - -@Component({ - templateUrl: 'postView.component.html', -}) -export class PostViewComponent implements OnInit, OnDestroy { - blockedUsers: string[]; - blanketText = `

Fyre Blanket

`; - commentCount = 0; - componentDestroyed: Subject = new Subject(); - currentArea: string; - isCopied = false; - imageData: any = null; - loading: boolean; - loggedIn: boolean; - parsedCommentArray: string[] = []; - post: Post; - userID: number; - wait = true; - - constructor( - private cdRef: ChangeDetectorRef, - private dialog: MatDialog, - private route: ActivatedRoute, - private router: Router, - private snackBar: MatSnackBar, - private commentService: CommentService, - private flagService: FlagService, - private navBarService: NavBarService, - private postService: PostService, - private profileService: ProfileService, - private routeService: RouteService, - ) { } - - ngOnInit() { - this.loading = true; - - this.blockedUsers = []; - if (window.localStorage.getItem('blockedUsers')) { - this.blockedUsers = window.localStorage.getItem('blockedUsers').split(','); - this.blockedUsers.pop(); - } - - this.profileService.getSelf() - .takeUntil(this.componentDestroyed) - .subscribe( (author: Author) => { - this.userID = author.user; - this.loggedIn = true; - }); - - this.navBarService.comment - .takeUntil(this.componentDestroyed) - .subscribe((comment: CommentData) => { - this.cdRef.detectChanges(); - if (!this.wait) { - if (comment.comment !== '' && this.runImageCheck(comment.comment)) { - if (comment.image) { - this.postService.setPicture(comment.image, this.post, this.currentArea, false, comment.comment) - .takeUntil(this.componentDestroyed) - .subscribe(result2 => { - if (!result2.getError()) { - this.post.comments.push(result2); - this.navBarService.clearInputs.next(true); - } else { - this.snackBar.open('Your image file must be below 512KiB in size', 'Close', { - duration: 3000 - }); - } - }); - } else { - this.postService.comment(this.currentArea, this.post, comment.comment) - .takeUntil(this.componentDestroyed) - .subscribe(); - this.navBarService.clearInputs.next(true); - } - this.commentCount += 1; - this.cdRef.detectChanges(); - } else { - this.snackBar.open( - 'Please enter something' - , 'Close', { - duration: 3000 - }); - this.navBarService.clearInputs.next(false); - } - } - this.wait = false; - }); - - this.route.params - .takeUntil(this.componentDestroyed) - .subscribe(params => { - this.currentArea = params['area']; - - this.postService.getPost(this.currentArea, params['id']) - .takeUntil(this.componentDestroyed) - .subscribe(post => { - this.post = post; - this.commentCount = this.post.comments.length; - this.loading = false; - this.navBarService.hasPost.next(true); - this.cdRef.detectChanges(); - }); - - let commentIDArray = params['comments']; - commentIDArray = commentIDArray + '-'; - - if (commentIDArray) { - while (commentIDArray.indexOf('-') !== -1) { - this.parsedCommentArray.push(commentIDArray.slice(0, commentIDArray.indexOf('-'))); - commentIDArray = commentIDArray.slice(commentIDArray.indexOf('-') + 1, commentIDArray.length); - } - } - }); - this.cdRef.detectChanges(); - } - - ngOnDestroy() { - this.cdRef.detach(); - this.componentDestroyed.next(true); - this.componentDestroyed.complete(); - } - - back() { - if (this.routeService.routes.length === 0) { - this.router.navigateByUrl(''); - } else { - this.router.navigateByUrl(this.routeService.getNextRoute()); - } - } - - blockUser(id: number) { - const dialogRef = this.dialog.open(ConfirmDeletionDialogComponent); - dialogRef.afterClosed() - .takeUntil(this.componentDestroyed) - .subscribe(result => { - if (result.bool) { - if (window.localStorage.getItem('blockedUsers')) { - window.localStorage.setItem('blockedUsers', window.localStorage.getItem('blockedUsers') + String(id + ',')); - } else { - window.localStorage.setItem('blockedUsers', String(id + ',')); - } - this.ngOnInit(); - } - }); - } - - unblockUser(id: number) { - const dialogRef = this.dialog.open(ConfirmDeletionDialogComponent); - dialogRef.afterClosed() - .takeUntil(this.componentDestroyed) - .subscribe(result => { - if (result.bool) { - if (window.localStorage.getItem('blockedUsers')) { - window.localStorage.setItem('blockedUsers', window.localStorage.getItem('blockedUsers').replace(id + ',', '')); - } - this.ngOnInit(); - } - }); - } - - getCommentLength(nLength: number) { - if (nLength.toString().length === 4) { - return nLength.toString().slice(0, 1) + 'K'; - } else if (nLength.toString().length === 5) { - return nLength.toString().slice(0, 2) + 'K'; - } else if (nLength.toString().length >= 6) { - return '\u221E'; - } else { - return nLength.toString(); - } - } - - getImageMatchesByGroup(index: number, str: string, reg: RegExp): string[] { - let match: any; - const matches: string[] = []; - // Find any occurence of image markdown - while ((match = reg.exec(str))) { - if (match[index] !== undefined) { - matches.push(match[index]); - } - } - return matches; - } - - gotoUser(user: string) { - this.routeService.addNextRoute(this.router.url); - this.router.navigateByUrl('/user/' + user); - } - - isBlockedUser(c: number) { - return this.blockedUsers.includes(String(c)); - } - - notificationIndication(commentID: number) { - if (this.parsedCommentArray.indexOf(commentID.toString()) !== -1) { - return '2px solid #ed763e'; - } else { - return ''; - } - } - - openCommentDeleteDialog(c: Comment) { - const dialogRef = this.dialog.open(ConfirmDeletionDialogComponent); - dialogRef.afterClosed() - .takeUntil(this.componentDestroyed) - .subscribe(result => { - if (result.bool) { - this.commentService.deleteComment( - this.currentArea, - this.post, - c - ); - this.commentCount -= 1; - this.snackBar.open('Comment deleted successfully', 'Close', { - duration: 3000 - }); - } - }); - } - - openFlagDialog(comment: Comment, typeOfFlagReport: TypeOfReport) { - this.flagService.currentComment = comment; - this.flagService.currentPost = this.post; - - const dialogRef = this.dialog.open(FlagDialogComponent); - dialogRef.componentInstance.typeOfReport = typeOfFlagReport; - - dialogRef.afterClosed() - .takeUntil(this.componentDestroyed) - .subscribe(result => { - this.flagService.sendFlagReport(result.typeOfReport, result.report, result.choice, result.area); - }); - } - - openPostDeleteDialog() { - const dialogRef = this.dialog.open(ConfirmDeletionDialogComponent); - dialogRef.afterClosed() - .takeUntil(this.componentDestroyed) - .subscribe(result => { - if (result.bool) { - this.postService.deletePost(this.currentArea, this.post.id, false); - this.snackBar.open('Post deleted successfully', 'Close', { - duration: 3000 - }); - this.router.navigateByUrl(this.routeService.getNextRoute()); - } - }); - } - - runImageCheck(comment: string): boolean { - this.cdRef.detectChanges(); - const linkMatch = this.getImageMatchesByGroup(1, comment, C.WF_IMAGE_REGEX); - // Find duplicates and invalids - if (linkMatch.length > 0) { - return false; - } - return true; - } - - share(commentID: number) { - let commentURL = ''; - let authorName = this.post.author.name; - let description = this.post.text.slice(0, 100); - - if (commentID !== undefined) { - commentURL = '/' + commentID.toString(); - - for (let i = 0; i < this.post.comments.length; i++) { - if (this.post.comments[i].id === commentID) { - authorName = this.post.comments[i].author.name; - description = this.post.comments[i].text.slice(0, 100); - } - } - } - - this.navBarService.link.next( - new Link('https://client.wildfyre.net/areas/' + this.currentArea + '/' + this.post.id + commentURL, - description, - authorName - )); - const dialogRef = this.dialog.open(ShareDialogComponent); - dialogRef.afterClosed() - .takeUntil(this.componentDestroyed) - .subscribe(result => { - if (result.isLink) { - this.snackBar.open('Link copied successfully', 'Close', { - duration: 3000 - }); - } - }); - } - - subscribe(s: boolean) { - this.postService.subscribe(this.currentArea, this.post, s) - .takeUntil(this.componentDestroyed) - .subscribe(); - } -} diff --git a/src/app/profile/profile.component.html b/src/app/profile/profile.component.html deleted file mode 100644 --- a/src/app/profile/profile.component.html +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - -
-

You are currently banned

-
-
-
-
- Reason: {{getReason(ban.reason)}}
- {{ban.comment}}
- You can not - post, comment, or flag. - post - or - comment - or - flag. -
- {{ban.timestamp}}
-
- Expires: {{ban.expiry}} -
-
-
- - - - - Avatar of {{author?.name}} - Avatar of {{author?.name}} -
-
-
- {{author?.name}}
- - {{account?.email}} - -
-
-
- - - -
ID: {{author?.user}}
diff --git a/src/app/profile/profile.component.ts b/src/app/profile/profile.component.ts deleted file mode 100644 --- a/src/app/profile/profile.component.ts +++ /dev/null @@ -1,222 +0,0 @@ -import { Component, OnInit, OnDestroy, ViewChild, ChangeDetectorRef } from '@angular/core'; -import { MatDialog, MatDialogRef, MatSnackBar } from '@angular/material'; -import { Router, ActivatedRoute } from '@angular/router'; -import { Subject } from 'rxjs/Subject'; -import { AvatarDialogComponent } from '../_dialogs/avatar.dialog.component'; -import { BioDialogComponent } from '../_dialogs/bio.dialog.component'; -import { EmailDialogComponent } from '../_dialogs/email.dialog.component'; -import { PasswordDialogComponent } from '../_dialogs/password.dialog.component'; -import { Account } from '../_models/account'; -import { Author } from '../_models/author'; -import { Ban } from '../_models/ban'; -import { Choice } from '../_models/choice'; -import { SuperBan } from '../_models/superBan'; -import { AuthenticationService } from '../_services/authentication.service'; -import { ProfileService } from '../_services/profile.service'; -import { ReasonService } from '../_services/reason.service'; -import { RouteService } from '../_services/route.service'; - -@Component({ - templateUrl: 'profile.component.html' -}) -export class ProfileComponent implements OnInit, OnDestroy { - account: Account; - author: Author; - choices: Choice[]; - componentDestroyed: Subject = new Subject(); - data: any; - index = 1; - limit = 2; - loading = true; - model: any = {}; - offset = 2; - url: string; - self: boolean; - bans: Ban[] = []; - totalCount = 0; - - constructor( - private cdRef: ChangeDetectorRef, - private dialog: MatDialog, - private route: ActivatedRoute, - private router: Router, - public snackBar: MatSnackBar, - private authenticationService: AuthenticationService, - private profileService: ProfileService, - private reasonService: ReasonService, - private routeService: RouteService - ) { } - - ngOnInit() { - this.reasonService.getFlagReasons() - .takeUntil(this.componentDestroyed) - .subscribe((choices) => { - this.choices = choices; - }); - this.routeService.resetRoutes(); - this.route.params - .takeUntil(this.componentDestroyed) - .subscribe((parms) => { - if (parms['id']) { - this.profileService.getUser(parms['id']) - .takeUntil(this.componentDestroyed) - .subscribe((user: Author) => { - this.self = false; - this.author = user; - }); - } else { - this.self = true; - - this.profileService.getSelf() - .takeUntil(this.componentDestroyed) - .subscribe((self: Author) => { - this.author = self; - this.model.bio = this.author.bio; - }); - - this.profileService.getAccount() - .takeUntil(this.componentDestroyed) - .subscribe((self: Account) => { - this.account = self; - this.model.email = this.account.email; - }); - - this.profileService.getBans(this.limit, (this.index * this.limit) - this.limit) - .takeUntil(this.componentDestroyed) - .subscribe((superBan: SuperBan) => { - superBan.results.forEach((obj: any) => { - this.bans.push(Ban.parse(obj)); - }); - this.totalCount = superBan.count; - this.cdRef.detectChanges(); - }); - - } - }); - - this.profileService.getAccount() - .takeUntil(this.componentDestroyed) - .subscribe((self: Account) => { - this.account = self; - this.model.email = this.account.email; - this.self = true; - }); - this.loading = false; - } - - ngOnDestroy() { - this.cdRef.detach(); - this.componentDestroyed.next(true); - this.componentDestroyed.complete(); - } - - getBans(page: number) { - this.loading = true; - this.bans = []; - - this.profileService.getBans(this.limit, (this.offset * page) - this.limit) - .takeUntil(this.componentDestroyed) - .subscribe(superBan => { - - superBan.results.forEach((obj: any) => { - this.bans.push(Ban.parse(obj)); - }); - - this.index = page; - this.totalCount = superBan.count; - this.cdRef.detectChanges(); - this.loading = false; - }); - } - - getReason(number: number): string { - if (number !== null) { - return this.choices[number].value; - } else { - return this.choices[3].value; - } - } - - openBioDialog() { - const dialogRef = this.dialog.open(BioDialogComponent); - dialogRef.componentInstance.model.bio = this.author.bio; - dialogRef.afterClosed() - .takeUntil(this.componentDestroyed) - .subscribe(result => { - if (result.bool) { - this.profileService.setBio(this.author, result.bio) - .takeUntil(this.componentDestroyed) - .subscribe(); - const snackBarRef = this.snackBar.open('Bio changed successfully', 'Close', { - duration: 3000 - }); - } - }); - } - - openEmailDialog() { - const dialogRef = this.dialog.open(EmailDialogComponent); - dialogRef.componentInstance.model.email = this.account.email; - dialogRef.afterClosed() - .takeUntil(this.componentDestroyed) - .subscribe(result => { - if (result.bool) { - this.profileService.setEmail(result.email) - .takeUntil(this.componentDestroyed) - .subscribe(); - const snackBarRef = this.snackBar - .open('We just sent you a verification email, you must verify your email for it to be set', 'Close', { - duration: 3000 - }); - } - }); - } - - openPasswordDialog() { - const dialogRef = this.dialog.open(PasswordDialogComponent); - dialogRef.componentInstance.account = this.account; - dialogRef.componentInstance.author = this.author; - dialogRef.afterClosed() - .takeUntil(this.componentDestroyed) - .subscribe(result => { - if (result.bool) { - const snackBarRef = this.snackBar.open('Password changed successfully', 'Close', { - duration: 3000 - }); - } - }); - } - - openPictureDialog() { - const dialogRef = this.dialog.open(AvatarDialogComponent); - dialogRef.componentInstance.author = this.author; - dialogRef.afterClosed() - .takeUntil(this.componentDestroyed) - .subscribe(result => { - if (result.bool) { - if (result.profilePicture) { - this.profileService.setProfilePicture(result.profilePicture) - .takeUntil(this.componentDestroyed) - .subscribe(result2 => { - if (!result2.getError()) { - this.author.avatar = result2.avatar; - } else { - const snackBarRef = this.snackBar.open('Your image file must be below 512KiB in size', 'Close', { - duration: 3000 - }); - } - }); - } else { - const snackBarRef = this.snackBar.open('You did not select a valid image file', 'Close', { - duration: 3000 - }); - } - } - }); - } - - viewProfile() { - this.routeService.addNextRoute(this.router.url); - this.router.navigateByUrl('/user/' + this.author.user); - } - } diff --git a/src/app/profileView/profileView.component.html b/src/app/profileView/profileView.component.html deleted file mode 100644 --- a/src/app/profileView/profileView.component.html +++ /dev/null @@ -1,18 +0,0 @@ -
arrow_back
- - -
- User is currently banned -
- Avatar of {{author?.name}} - Avatar of {{author?.name}} -
-
- {{author?.name}}
-
-
-
- - - -
ID: {{author?.user}}
diff --git a/src/app/profileView/profileView.component.spec.ts b/src/app/profileView/profileView.component.spec.ts deleted file mode 100644 --- a/src/app/profileView/profileView.component.spec.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { ComponentFixture, TestBed, async } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { DebugElement } from '@angular/core'; -import { Observable } from 'rxjs'; -import { ProfileViewComponent } from './profileView.component'; -import { Router, ActivatedRoute } from '@angular/router'; -import { AuthenticationService } from '../_services/authentication.service'; -import { ProfileService } from '../_services/profile.service'; -import { RouteService } from '../_services/route.service'; -import { MatCardModule, MatDialogModule, MatIconModule } from '@angular/material'; -import { MarkedPipe } from '../_pipes/marked.pipe'; -import { Author } from '../_models/author'; -import { NavBarService } from '../_services/navBar.service'; - -describe('ProfileViewComponent', () => { - let comp: ProfileViewComponent; - let fixture: ComponentFixture; - let de: DebugElement; - let el: HTMLElement; - - beforeEach(() => { - // stubs - const activatedRouteStub = { - params: Observable.of({'id': 1}) - }; - const routerStub = {}; - const authenticationServiceStub = { - token: 'token' - }; - const profileServiceStub = { - getUser: (id: number) => { - if (id !== 1) { - throw new Error('Requests for users other than with Id 1 not implemented'); - } - - return Observable.of( - new Author(1, 'Test User', null, 'test', false) - ); - } - }; - const navBarServiceStub = {}; - const routeServiceStub = {}; - - TestBed.configureTestingModule({ - declarations: [ ProfileViewComponent, MarkedPipe ], - providers: [ - { provide: ActivatedRoute, useValue: activatedRouteStub }, - { provide: Router, useValue: routerStub }, - { provide: AuthenticationService, useValue: authenticationServiceStub }, - { provide: ProfileService, useValue: profileServiceStub }, - { provide: RouteService, useValue: routeServiceStub }, - { provide: NavBarService, useValue: navBarServiceStub } - ], - imports: [ MatCardModule, MatDialogModule, MatIconModule ], - }); - - fixture = TestBed.createComponent(ProfileViewComponent); - comp = fixture.componentInstance; - - de = fixture.debugElement.query(By.css('#name')); - el = de.nativeElement; - }); - - it('should set the author name', async(() => { - fixture.detectChanges(); - - fixture.whenStable().then(() => { - fixture.detectChanges(); - - expect(el.textContent).toBe('Test User'); - }); - })); - - it('should set bio', async(() => { - fixture.detectChanges(); - - fixture.whenStable().then(() => { - fixture.detectChanges(); - - expect(fixture.debugElement.query(By.css('#bio')).nativeElement.textContent).toBe('test\n'); - }); - })); - - it('should set id', async(() => { - fixture.detectChanges(); - - fixture.whenStable().then(() => { - fixture.detectChanges(); - - expect(fixture.debugElement.query(By.css('#userID')).nativeElement.textContent).toBe('ID: 1'); - }); - })); - -}); diff --git a/src/app/profileView/profileView.component.ts b/src/app/profileView/profileView.component.ts deleted file mode 100644 --- a/src/app/profileView/profileView.component.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Component, OnInit, OnDestroy } from '@angular/core'; -import { MatDialog, MatDialogRef } from '@angular/material'; -import { Router, ActivatedRoute } from '@angular/router'; -import { Subject } from 'rxjs/Subject'; -import { ShareDialogComponent } from '../_dialogs/share.dialog.component'; -import { Author } from '../_models/author'; -import { Link } from '../_models/link'; -import { AuthenticationService } from '../_services/authentication.service'; -import { NavBarService } from '../_services/navBar.service'; -import { ProfileService } from '../_services/profile.service'; -import { RouteService } from '../_services/route.service'; - -@Component({ - templateUrl: 'profileView.component.html', -}) -export class ProfileViewComponent implements OnInit, OnDestroy { - author: Author; - componentDestroyed: Subject = new Subject(); - - constructor( - private dialog: MatDialog, - private route: ActivatedRoute, - private router: Router, - private authenticationService: AuthenticationService, - private navBarService: NavBarService, - private profileService: ProfileService, - private routeService: RouteService - ) { } - - ngOnInit() { - this.route.params - .takeUntil(this.componentDestroyed) - .subscribe(params => { - const id = params['id']; - - // Get post from secure api end point - this.profileService.getUser(id) - .takeUntil(this.componentDestroyed) - .subscribe(author => { - this.author = author; - }); - }); - } - - ngOnDestroy() { - this.componentDestroyed.next(true); - this.componentDestroyed.complete(); - } - - back() { - if (this.routeService.routes.length === 0) { - this.router.navigateByUrl(''); - } else { - this.router.navigateByUrl(this.routeService.getNextRoute()); - } - } - - share() { - this.navBarService.link.next( - new Link('https://client.wildfyre.net/user/' + this.author.user, - this.author.bio.slice(0, 100), - this.author.name - )); - const dialogRef = this.dialog.open(ShareDialogComponent); - dialogRef.afterClosed() - .takeUntil(this.componentDestroyed) - .subscribe(result => { }); - } -} diff --git a/src/app/recover/recover.component.html b/src/app/recover/recover.component.html deleted file mode 100644 --- a/src/app/recover/recover.component.html +++ /dev/null @@ -1,78 +0,0 @@ - - - -

Recover

- - - - - Recover your Username - - -
- account_circle -
-
- - - -
-
    -
  • {{err}}
  • -
-
-
- -
-
    -
  • {{err}}
  • -
-
-
- - - - -
- - - - Recover your Password - - -
- lock -
-
- - - -
-
    -
  • {{err}}
  • -
-
- - - -
-
    -
  • {{err}}
  • -
-
-
- -
-
    -
  • {{err}}
  • -
-
-
- - - - -
-
-
-
diff --git a/src/app/recover/recover.component.spec.ts b/src/app/recover/recover.component.spec.ts deleted file mode 100644 --- a/src/app/recover/recover.component.spec.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { ComponentFixture, TestBed, inject } from '@angular/core/testing'; -import { NgModel, NgForm } from '@angular/forms'; -import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { MatSnackBar } from '@angular/material'; -import { Router } from '@angular/router'; -import { RegistrationService } from '../_services/registration.service'; -import { RecoverComponent } from './recover.component'; - -describe('RecoverComponent', () => { - let comp: RecoverComponent; - let fixture: ComponentFixture; - - beforeEach(() => { - const mdSnackBarStub = { - open: () => ({}) - }; - const routerStub = { - navigateByUrl: () => ({}) - }; - const registrationServiceStub = { - recoverPasswordStep1: () => ({ - subscribe: () => ({}) - }), - recoverUsername: () => ({ - subscribe: () => ({}) - }) - }; - TestBed.configureTestingModule({ - declarations: [ RecoverComponent, NgForm, NgModel ], - schemas: [ NO_ERRORS_SCHEMA ], - providers: [ - { provide: MatSnackBar, useValue: mdSnackBarStub }, - { provide: Router, useValue: routerStub }, - { provide: RegistrationService, useValue: registrationServiceStub } - ] - }); - fixture = TestBed.createComponent(RecoverComponent); - comp = fixture.componentInstance; - }); - - it('can load instance', () => { - expect(comp).toBeTruthy(); - }); - - it('loading defaults to: false', () => { - expect(comp.loading).toEqual(false); - }); - - it('should create', inject([RegistrationService], (registrationService: RegistrationService) => { - spyOn(registrationService, 'recoverPasswordStep1').and.returnValue({subscribe: () => {}}); - expect(comp).toBeTruthy(); - })); - - it('should create', inject([RegistrationService], (registrationService: RegistrationService) => { - spyOn(registrationService, 'recoverUsername').and.returnValue({subscribe: () => {}}); - expect(comp).toBeTruthy(); - })); - -}); diff --git a/src/app/recover/recover.component.ts b/src/app/recover/recover.component.ts deleted file mode 100644 --- a/src/app/recover/recover.component.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { Component, OnDestroy } from '@angular/core'; -import { MatSnackBar } from '@angular/material'; -import { Router } from '@angular/router'; -import { Subject } from 'rxjs/Subject'; -import { ViewChild } from '@angular/core'; -import { RecoverTransaction, RecoverTransactionError } from '../_models/recoverTransaction'; -import { RegistrationService } from '../_services/registration.service'; -import { ReCaptchaComponent } from 'angular2-recaptcha'; - -@Component({ - templateUrl: 'recover.component.html' -}) -export class RecoverComponent implements OnDestroy { - @ViewChild(ReCaptchaComponent) captcha: ReCaptchaComponent; - - componentDestroyed: Subject = new Subject(); - errors: RecoverTransactionError; - loading = false; - model: any = {}; - token: any; - transID: string; - - constructor( - private snackBar: MatSnackBar, - private router: Router, - private registrationService: RegistrationService - ) { } - - ngOnDestroy() { - this.componentDestroyed.next(true); - this.componentDestroyed.complete(); - } - - recoverPassword() { - this.registrationService.recoverPasswordStep1(this.model.email2, this.model.username, this.token) - .takeUntil(this.componentDestroyed) - .subscribe(result => { - if (!result.getError()) { - this.router.navigateByUrl('/recover/password/' + result.transaction); - this.loading = false; - this.model.email2 = ''; - this.model.username = ''; - this.captcha.reset(); - } else { - this.errors = result.getError(); - this.loading = false; - this.captcha.reset(); - } - }); - } - - recoverUsername() { - this.registrationService.recoverUsername(this.model.email, this.token) - .takeUntil(this.componentDestroyed) - .subscribe(result => { - if (!result.getError()) { - const snackBarRef = this.snackBar.open('We will contact you via the information provided', 'Close', { - duration: 3000 - }); - this.loading = false; - this.model.email = ''; - this.captcha.reset(); - } else { - this.errors = result.getError(); - this.loading = false; - this.captcha.reset(); - } - }); - } - - setCaptchaResponse(res: any) { - this.token = res; - } -} diff --git a/src/app/recoverPassword/recoverPassword.component.html b/src/app/recoverPassword/recoverPassword.component.html deleted file mode 100644 --- a/src/app/recoverPassword/recoverPassword.component.html +++ /dev/null @@ -1,72 +0,0 @@ - - - -

Recover Password

-
-

Warning!

- Do not close this webpage or you will have to restart!
- We sent a Password Reset Token to you via the information provided.
- You must have it in order to continue using this form! -
-
- Passwords must contain at least 8 characters and be alphanumeric (At least 1 letter and 1 number) -
-
-
-
    -
  • {{err}}
  • -
-
- -
- - - -
Token is required
-
-
    -
  • {{err}}
  • -
-
-
- -
- - - -
Password is required
-
-
    -
  • {{err}}
  • -
-
-
- -
- - - -
Password is required
-
-
    -
  • {{err}}
  • -
-
-
- -
- -
-
    -
  • {{err}}
  • -
-
-
-
- - -
-
- -
-
diff --git a/src/app/recoverPassword/recoverPassword.component.spec.ts b/src/app/recoverPassword/recoverPassword.component.spec.ts deleted file mode 100644 --- a/src/app/recoverPassword/recoverPassword.component.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { ComponentFixture, TestBed, inject } from '@angular/core/testing'; -import { NgModel, NgForm } from '@angular/forms'; -import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { MatSnackBar } from '@angular/material'; -import { Router } from '@angular/router'; -import { ActivatedRoute } from '@angular/router'; -import { RegistrationService } from '../_services/registration.service'; -import { RecoverPasswordComponent } from './recoverPassword.component'; - -describe('RecoverPasswordComponent', () => { - let comp: RecoverPasswordComponent; - let fixture: ComponentFixture; - - beforeEach(() => { - const mdSnackBarStub = { - open: () => ({}) - }; - const routerStub = { - navigateByUrl: () => ({}) - }; - const activatedRouteStub = { - params: { - subscribe: () => ({}) - } - }; - const registrationServiceStub = { - recoverPasswordStep2: () => ({ - subscribe: () => ({}) - }) - }; - TestBed.configureTestingModule({ - declarations: [ RecoverPasswordComponent, NgForm, NgModel ], - schemas: [ NO_ERRORS_SCHEMA ], - providers: [ - { provide: MatSnackBar, useValue: mdSnackBarStub }, - { provide: Router, useValue: routerStub }, - { provide: ActivatedRoute, useValue: activatedRouteStub }, - { provide: RegistrationService, useValue: registrationServiceStub } - ] - }); - fixture = TestBed.createComponent(RecoverPasswordComponent); - comp = fixture.componentInstance; - }); - - it('can load instance', () => { - expect(comp).toBeTruthy(); - }); - - it('loading defaults to: false', () => { - expect(comp.loading).toEqual(false); - }); - - it('should create', inject([RegistrationService], (registrationService: RegistrationService) => { - spyOn(registrationService, 'recoverPasswordStep2').and.returnValue({subscribe: () => {}}); - expect(comp).toBeTruthy(); - })); - -}); diff --git a/src/app/recoverPassword/recoverPassword.component.ts b/src/app/recoverPassword/recoverPassword.component.ts deleted file mode 100644 --- a/src/app/recoverPassword/recoverPassword.component.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { Component, OnInit, OnDestroy } from '@angular/core'; -import { MatSnackBar } from '@angular/material'; -import { Router, ActivatedRoute } from '@angular/router'; -import { Subject } from 'rxjs/Subject'; -import { ViewChild } from '@angular/core'; -import { ResetError } from '../_models/reset'; -import { RegistrationService } from '../_services/registration.service'; -import { ReCaptchaComponent } from 'angular2-recaptcha'; - -@Component({ - templateUrl: 'recoverPassword.component.html' -}) -export class RecoverPasswordComponent implements OnInit, OnDestroy { - @ViewChild(ReCaptchaComponent) captcha: ReCaptchaComponent; - - componentDestroyed: Subject = new Subject(); - errors: ResetError; - loading = false; - model: any = {}; - token: any; - transactionID: string; - - constructor( - private snackBar: MatSnackBar, - private route: ActivatedRoute, - private router: Router, - private registrationService: RegistrationService - ) { } - - ngOnInit() { - this.route.params - .subscribe(params => { - this.transactionID = params['trans']; - }); - } - - ngOnDestroy() { - this.componentDestroyed.next(true); - this.componentDestroyed.complete(); - } - - resetPassword() { - if (this.model.password === this.model.password2) { - this.registrationService.recoverPasswordStep2(this.model.password, this.model.token, this.transactionID, this.token) - .takeUntil(this.componentDestroyed) - .subscribe(result => { - if (!result.getError()) { - const snackBarRef = this.snackBar.open('Your new password is now set', 'Close', { - duration: 3000 - }); - this.router.navigateByUrl('login'); - this.loading = false; - this.model.password = ''; - this.model.password2 = ''; - this.model.token = ''; - this.captcha.reset(); - } else { - const snackBarRef = this.snackBar.open('You inputted something incorrectly', 'Close', { - duration: 3000 - }); - this.errors = result.getError(); - this.loading = false; - this.captcha.reset(); - } - }); - } else { - const snackBarRef = this.snackBar.open('Your passwords did not match', 'Close', { - duration: 3000 - }); - this.model.password = ''; - this.model.password2 = ''; - } - } - - setCaptchaResponse(res: any) { - this.token = res; - } -} diff --git a/src/app/register/register.component.html b/src/app/register/register.component.html deleted file mode 100644 --- a/src/app/register/register.component.html +++ /dev/null @@ -1,81 +0,0 @@ - - - -
- Usernames must use Letters, Digits and @/./+/-/_ only.
- Passwords must contain at least 8 characters and be alphanumeric (At least 1 letter and 1 number) -
-

Register

-
-
-
    -
  • {{err}}
  • -
-
- -
- - - -
Username is required
-
-
    -
  • {{err}}
  • -
-
-
- -
- - - -
Email is required
-
-
    -
  • {{err}}
  • -
-
-
- -
- - - -
Password is required
-
-
    -
  • {{err}}
  • -
-
-
- -
- - - -
Second password is required
-
-
    -
  • {{err}}
  • -
-
-
- -
- -
-
    -
  • {{err}}
  • -
-
-
-
-
- By clicking Register, you agree to our Terms - and that you have read our Privacy Policy. - - -
-
-
-
diff --git a/src/app/register/register.component.spec.ts b/src/app/register/register.component.spec.ts deleted file mode 100644 --- a/src/app/register/register.component.spec.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { ComponentFixture, TestBed, inject } from '@angular/core/testing'; -import { FormsModule } from '@angular/forms'; -import { MatSnackBarModule } from '@angular/material'; -import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { Router } from '@angular/router'; -import { AuthenticationService } from '../_services/authentication.service'; -import { RegistrationService } from '../_services/registration.service'; -import { RegisterComponent } from './register.component'; - -describe('RegisterComponent', () => { - let comp: RegisterComponent; - let fixture: ComponentFixture; - - beforeEach(() => { - const routerStub = { - navigate: () => ({}) - }; - const authenticationServiceStub = { - logout: () => ({}) - }; - const registrationServiceStub = { - register: () => ({ - subscribe: () => ({}) - }) - }; - TestBed.configureTestingModule({ - declarations: [ RegisterComponent ], - schemas: [ NO_ERRORS_SCHEMA ], - providers: [ - { provide: Router, useValue: routerStub }, - { provide: AuthenticationService, useValue: authenticationServiceStub }, - { provide: RegistrationService, useValue: registrationServiceStub } - ], - imports: [ FormsModule, MatSnackBarModule ] - }); - fixture = TestBed.createComponent(RegisterComponent); - comp = fixture.componentInstance; - }); - - it('can load instance', () => { - expect(comp).toBeTruthy(); - }); - - it('loading defaults to: false', () => { - expect(comp.loading).toEqual(false); - }); - - describe('ngOnInit', () => { - it('makes expected calls', () => { - const authenticationServiceStub = fixture.debugElement.injector.get(AuthenticationService); - spyOn(authenticationServiceStub, 'logout'); - comp.ngOnInit(); - expect(authenticationServiceStub.logout).toHaveBeenCalled(); - }); - }); - - it('should create', inject([RegistrationService], (registrationService: RegistrationService) => { - spyOn(registrationService, 'register').and.returnValue({subscribe: () => {}}); - expect(comp).toBeTruthy(); - })); - -}); diff --git a/src/app/register/register.component.ts b/src/app/register/register.component.ts deleted file mode 100644 --- a/src/app/register/register.component.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { Component, OnInit, OnDestroy } from '@angular/core'; -import { MatSnackBar } from '@angular/material'; -import { Router } from '@angular/router'; -import { Subject } from 'rxjs/Subject'; -import { ViewChild } from '@angular/core'; -import { RegistrationError } from '../_models/registration'; -import { AuthenticationService } from '../_services/authentication.service'; -import { RegistrationService } from '../_services/registration.service'; -import { ReCaptchaComponent } from 'angular2-recaptcha'; - -@Component({ - templateUrl: 'register.component.html' -}) -export class RegisterComponent implements OnInit, OnDestroy { - @ViewChild(ReCaptchaComponent) captcha: ReCaptchaComponent; - - componentDestroyed: Subject = new Subject(); - errors: RegistrationError; - loading = false; - model: any = {}; - token: any; - - constructor( - private snackBar: MatSnackBar, - private router: Router, - private authenticationService: AuthenticationService, - private registrationService: RegistrationService - ) { } - - ngOnInit() { - // Reset login status - this.authenticationService.logout(); - } - - ngOnDestroy() { - this.componentDestroyed.next(true); - this.componentDestroyed.complete(); - } - - register() { - this.loading = true; - - if (this.model.password === this.model.password2) { - this.registrationService.register(this.model.username, this.model.email, this.model.password, this.token) - .takeUntil(this.componentDestroyed) - .subscribe(result => { - if (!result.getError()) { - this.router.navigate(['/register/success']); - } else { - this.errors = result.getError(); - this.loading = false; - } - }); - } else { - this.loading = false; - const snackBarRef = this.snackBar.open('Your passwords do not match', 'Close', { - duration: 3000 - }); - } - } - setCaptchaResponse(res: any) { - this.token = this.captcha.getResponse(); - } -} diff --git a/src/app/registerSuccess/registerSuccess.component.html b/src/app/registerSuccess/registerSuccess.component.html deleted file mode 100644 --- a/src/app/registerSuccess/registerSuccess.component.html +++ /dev/null @@ -1,14 +0,0 @@ - - - -
- Registration Successful!
- We sent a verification email to you. - You can now log in! -
-
-
- -
-
-
diff --git a/src/app/registerSuccess/registerSuccess.component.ts b/src/app/registerSuccess/registerSuccess.component.ts deleted file mode 100644 --- a/src/app/registerSuccess/registerSuccess.component.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { Router } from '@angular/router'; -import { AuthenticationService } from '../_services/authentication.service'; - -@Component({ - templateUrl: 'registerSuccess.component.html' -}) -export class RegisterSuccessComponent implements OnInit { - loading: boolean; - - constructor( - private router: Router, - private authenticationService: AuthenticationService - ) { } - - ngOnInit() { - // Reset login status - this.authenticationService.logout(); - } - - letsGo() { - this.router.navigate(['/login']); - } -} diff --git a/src/app/userPosts/userPosts.component.html b/src/app/userPosts/userPosts.component.html deleted file mode 100644 --- a/src/app/userPosts/userPosts.component.html +++ /dev/null @@ -1,66 +0,0 @@ - - - No posts, try posting? - - -

- - - - - - - visibility_on - visibility_off - image - ... -
- {{post.created}} -
-
-
-
- - - - diff --git a/src/app/userPosts/userPosts.component.spec.ts b/src/app/userPosts/userPosts.component.spec.ts deleted file mode 100644 --- a/src/app/userPosts/userPosts.component.spec.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { By } from '@angular/platform-browser'; -import { ComponentFixture, ComponentFixtureAutoDetect, TestBed, async } from '@angular/core/testing'; -import { FormsModule } from '@angular/forms'; -import { MatCardModule, MatProgressSpinnerModule, MatSlideToggleModule } from '@angular/material'; -import { Router, ActivatedRoute } from '@angular/router'; -import { Observable } from 'rxjs'; -import { Author } from '../_models/author'; -import { Comment } from '../_models/comment'; -import { Post } from '../_models/post'; -import { MarkedPipe } from '../_pipes/marked.pipe'; -import { AreaService } from '../_services/area.service'; -import { AuthenticationService } from '../_services/authentication.service'; -import { NavBarService } from '../_services/navBar.service'; -import { PostService } from '../_services/post.service'; -import { RouteService } from '../_services/route.service'; -import { UserPostsComponent } from './userPosts.component'; -import { NgxMasonryModule } from '../_modules/ngx-masonry/ngx-masonry.module'; -import { NgxPaginationModule } from 'ngx-pagination'; - -describe('UserPostsComponent', () => { - let comp: UserPostsComponent; - let fixture: ComponentFixture; - - beforeEach(() => { - const routerStub = { - url: '/posts' - }; - const authenticationServiceStub = { - token: 'token' - }; - const activatedRouteStub = { - params: Observable.of({'id': 1}) - }; - const postServiceStub = { - getOwnPosts: () => { - return Observable.of( - new Array( - new Post(1, - new Author(1, 'test', null, 'test', false), false, false, '2017-07-22T12:03:23.465373Z', false, 'test', null, [], - new Array( - new Comment(1, - new Author(1, 'test', null, 'test', false), '2017-07-22T12:03:23.465373Z', 'test', null))) - ) - ); - } - }; - const areaServiceStub = { - isAreaChecked: {}, - currentAreaName: {}, - getAreaRep: () => ({ - subscribe: () => ({}) - }) - }; - const routeServiceStub = {}; - - const navBarServiceStub = {}; - - TestBed.configureTestingModule({ - declarations: [ UserPostsComponent, MarkedPipe ], - providers: [ - { provide: Router, useValue: routerStub }, - { provide: ActivatedRoute, useValue: activatedRouteStub }, - { provide: AreaService, useValue: areaServiceStub }, - { provide: AuthenticationService, useValue: authenticationServiceStub }, - { provide: NavBarService, useValue: navBarServiceStub }, - { provide: PostService, useValue: postServiceStub }, - { provide: RouteService, useValue: routeServiceStub }, - { provide: ComponentFixtureAutoDetect, useValue: true } - ], - imports: [ MatCardModule, MatProgressSpinnerModule, MatSlideToggleModule, FormsModule, NgxMasonryModule, NgxPaginationModule ], - }); - fixture = TestBed.createComponent(UserPostsComponent); - comp = fixture.componentInstance; - }); - - it('should set user posts', async(() => { - fixture.detectChanges(); - - fixture.whenStable().then(() => { - fixture.detectChanges(); - expect(fixture.debugElement.query(By.css('.funPosts')) - .nativeElement.textContent).toBe('test Sat Jul 22 2017 08:03:23 GMT-0400 (Eastern Daylight Time)'); - }); - })); - -}); diff --git a/src/app/userPosts/userPosts.component.ts b/src/app/userPosts/userPosts.component.ts deleted file mode 100644 --- a/src/app/userPosts/userPosts.component.ts +++ /dev/null @@ -1,222 +0,0 @@ -import { Component, OnInit, OnDestroy, NgModule, ChangeDetectorRef } from '@angular/core'; -import { Router, ActivatedRoute } from '@angular/router'; -import { Subject } from 'rxjs/Subject'; -import { Area } from '../_models/area'; -import * as C from '../_models/constants'; -import { Post } from '../_models/post'; -import { NavBarService } from '../_services/navBar.service'; -import { PostService } from '../_services/post.service'; -import { RouteService } from '../_services/route.service'; - -@Component({ - templateUrl: 'userPosts.component.html' -}) -export class UserPostsComponent implements OnInit, OnDestroy { - backupPosts: { [area: string]: Post[]; } = {}; - componentDestroyed: Subject = new Subject(); - currentArea: string; - imageArray: { [area: string]: string[]; } = {}; - index = 1; - limit = 10; - loading = true; - model: any = {}; - offset = 10; - searchArray: Post[] = []; - searching = false; - superPosts: { [area: string]: Post[]; } = {}; - totalCount = 0; - - constructor( - private cdRef: ChangeDetectorRef, - private route: ActivatedRoute, - private router: Router, - private navBarService: NavBarService, - private postService: PostService, - private routeService: RouteService - ) { } - - private imageInPosts(posts: Post[], area: string) { - this.imageArray[area] = []; - - for (let i = 0; i <= posts.length - 1; i++) { - // Find image markdown data in post.text - Guarenteed by Regex - const indexOfStart = posts[i].text.search(C.WF_IMAGE_REGEX); - if (indexOfStart !== -1) { - // Start at index and parse until we find a closing ')' char - for (let j = indexOfStart; j <= posts[i].text.length; j++) { - if (posts[i].text.charAt(j) === ']') { - // Add data to image array in specific area - this.imageArray[area][i] = posts[i].text.slice(indexOfStart, j + 1); - } - } - } - } - this.loading = false; - } - - private removeMarkdown(input: string) { - input = input - // Remove horizontal rules (stripListHeaders conflict with this rule, which is why it has been moved to the top) - .replace(/^(-\s*?|\*\s*?|_\s*?){3,}\s*$/gm, '[Horizontal-Rule]') - // Remove horizontal rules - .replace(/^(-\s*?|\*\s*?|_\s*?){3,}\s*$/gm, '') - // Header - .replace(/\n={2,}/g, '\n') - // Strikethrough - .replace(/~~/g, '') - // Fenced codeblocks - .replace(/`{3}.*\n/g, '') - // Remove HTML tags - .replace(/<[^>]*>/g, '') - // Remove setext-style headers - .replace(/^[=\-]{2,}\s*$/g, '') - // Remove footnotes? - .replace(/\[\^.+?\](\: .*?$)?/g, '') - .replace(/\s{0,2}\[.*?\]: .*?$/g, '') - // Remove images - .replace(C.WF_IMAGE_REGEX, '') - // Remove wildfyre images - .replace(/(\[img: \d\])/gm, '') - // Remove inline links - .replace(/\[(.*?)\][\[\(].*?[\]\)]/g, '$1') - // Remove blockquotes - .replace(/^\s{0,3}>\s?/g, '') - // Remove reference-style links? - .replace(/^\s{1,2}\[(.*?)\]: (\S+)( ".*?")?\s*$/g, '') - // Remove atx-style headers - .replace(/^(\n)?\s{0,}#{1,6}\s+| {0,}(\n)?\s{0,}#{0,} {0,}(\n)?\s{0,}$/gm, '$1$2$3') - // Remove emphasis (repeat the line to remove double emphasis) - .replace(/([\*_]{1,3})(\S.*?\S{0,1})\1/g, '$2') - .replace(/([\*_]{1,3})(\S.*?\S{0,1})\1/g, '$2') - // Remove code blocks - .replace(/(`{3,})(.*?)\1/gm, '$2') - // Remove inline code - .replace(/`(.+?)`/g, '$1') - // Replace two or more newlines with exactly two? Not entirely sure this belongs here... - .replace(/\n{2,}/g, '\n\n'); - return input; - } - - ngOnInit() { - this.cdRef.detectChanges(); - this.routeService.resetRoutes(); - this.routeService.addNextRoute('/posts'); - this.route.params - .takeUntil(this.componentDestroyed) - .subscribe(params => { - if (params['index'] !== undefined) { - this.index = params['index']; - } - }); - - this.navBarService.currentArea - .takeUntil(this.componentDestroyed) - .subscribe((currentArea: Area) => { - if (currentArea.name !== '') { - this.currentArea = currentArea.name; - if (!this.superPosts[currentArea.name]) { - this.superPosts[currentArea.name] = []; - } - if (!this.backupPosts[currentArea.name]) { - this.backupPosts[currentArea.name] = []; - } - this.loading = true; - const posts: Post[] = []; - - this.postService.getOwnPosts(currentArea.name, this.limit, 0) - .takeUntil(this.componentDestroyed) - .subscribe(superPost => { - superPost.results.forEach((obj: any) => { - posts.push(Post.parse(obj)); - }); - - // Removes binding to original 'superPost' variable - this.superPosts[currentArea.name] = JSON.parse(JSON.stringify(posts)); - this.backupPosts[currentArea.name] = posts; - this.totalCount = superPost.count; - - this.imageInPosts(this.superPosts[currentArea.name], currentArea.name); - - for (let i = 0; i <= this.backupPosts[currentArea.name].length - 1; i++) { - this.backupPosts[currentArea.name][i].text = this.removeMarkdown(this.backupPosts[currentArea.name][i].text); - } - this.cdRef.detectChanges(); - this.loading = false; - }); - } - }); - } - - ngOnDestroy() { - this.cdRef.detach(); - this.componentDestroyed.next(true); - this.componentDestroyed.complete(); - } - - getPosts(page: number) { - this.loading = true; - const posts: Post[] = []; - - this.postService.getOwnPosts(this.currentArea, this.limit, (this.offset * page) - this.limit) - .takeUntil(this.componentDestroyed) - .subscribe(superPost => { - superPost.results.forEach((obj: any) => { - posts.push(Post.parse(obj)); - }); - - // Removes binding to original 'superPost' variable - this.superPosts[this.currentArea] = JSON.parse(JSON.stringify(posts)); - this.backupPosts[this.currentArea] = posts; - this.imageInPosts(this.superPosts[this.currentArea], this.currentArea); - - for (let i = 0; i <= this.backupPosts[this.currentArea].length - 1; i++) { - this.backupPosts[this.currentArea][i].text = this.removeMarkdown(this.backupPosts[this.currentArea][i].text); - } - this.index = page; - this.totalCount = superPost.count; - this.cdRef.detectChanges(); - this.loading = false; - }); - } - - goto(postID: string) { - this.routeService.addNextRouteByIndex(this.index); - this.router.navigateByUrl('/areas/' + this.currentArea + '/' + postID); - } - -/* Removed as of D114 - searchInput() { - if (this.areaService.currentAreaName === 'fun') { - this.searchArray = []; - if (this.model.postText === '') { - this.searching = false; - this.cdRef.detectChanges(); - } else { - this.searching = true; - - for (let i = 0; i <= this.funPosts.length - 1; i++) { - if (this.funPosts[i].text.toLowerCase().includes(this.model.postText.toLowerCase())) { - this.searchArray.push(this.backupFunPosts[i]); - } - } - this.cdRef.detectChanges(); - } - } else { - this.searchArray = []; - if (this.model.postText === '') { - this.searching = false; - this.cdRef.detectChanges(); - } else { - this.searching = true; - - for (let i = 0; i <= this.infoPosts.length - 1; i++) { - if (this.infoPosts[i].text.toLowerCase().includes(this.model.postText.toLowerCase())) { - this.searchArray.push(this.backupInfoPosts[i]); - } - } - this.cdRef.detectChanges(); - } - } - } - */ -} diff --git a/src/assets/manifest.json b/src/assets/manifest.json --- a/src/assets/manifest.json +++ b/src/assets/manifest.json @@ -13,7 +13,7 @@ "type": "image/png" } ], - "theme_color": "#ed763e", + "theme_color": "#EA6C40", "description": "", "orientation": "any", "background_color": "#263238", diff --git a/src/index.html b/src/index.html --- a/src/index.html +++ b/src/index.html @@ -6,7 +6,7 @@ - + @@ -15,6 +15,8 @@ + + + + + + + + +