Skip to content
Commits on Source (20)
...@@ -49,6 +49,14 @@ ...@@ -49,6 +49,14 @@
"with": "src/environments/environment.prod.ts" "with": "src/environments/environment.prod.ts"
} }
] ]
},
"hmr": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.hmr.ts"
}
]
} }
} }
}, },
...@@ -60,6 +68,10 @@ ...@@ -60,6 +68,10 @@
"configurations": { "configurations": {
"production": { "production": {
"browserTarget": "v5.x:build:production" "browserTarget": "v5.x:build:production"
},
"hmr": {
"hmr": true,
"browserTarget": "v5.x:build:hmr"
} }
} }
}, },
......
...@@ -1401,6 +1401,12 @@ ...@@ -1401,6 +1401,12 @@
"tslib": "^1.9.0" "tslib": "^1.9.0"
} }
}, },
"@angularclass/hmr": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@angularclass/hmr/-/hmr-2.1.3.tgz",
"integrity": "sha1-NOZY7T2jfyOwogDi2lqJvpK7IJ8=",
"dev": true
},
"@babel/code-frame": { "@babel/code-frame": {
"version": "7.0.0", "version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
...@@ -5787,6 +5793,11 @@ ...@@ -5787,6 +5793,11 @@
"integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=",
"dev": true "dev": true
}, },
"dialog-polyfill": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/dialog-polyfill/-/dialog-polyfill-0.5.0.tgz",
"integrity": "sha512-fOj68T8KB6UIsDFmK7zYbmORJMLYkRmtsLM1W6wbCVUWu4Hdcud5bqbvuueTxO84JXtK9HcpCHV9vNwlWUdCIw=="
},
"diff": { "diff": {
"version": "3.5.0", "version": "3.5.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
"build": "ng build --prod", "build": "ng build --prod",
"prebuild-dev": "gulp build.sass --deploy-url=http://localhost/en", "prebuild-dev": "gulp build.sass --deploy-url=http://localhost/en",
"build-dev": "ng build --output-path dist/en --deploy-url=/en/ --watch=true --poll=800", "build-dev": "ng build --output-path dist/en --deploy-url=/en/ --watch=true --poll=800",
"serve-dev": "ng serve --host=0.0.0.0 --deploy-url=/en/ --configuration=hmr --hmr --poll=800 --progress",
"test": "ng test", "test": "ng test",
"lint": "ng lint", "lint": "ng lint",
"e2e": "cypress run --debug", "e2e": "cypress run --debug",
...@@ -57,6 +58,7 @@ ...@@ -57,6 +58,7 @@
"@angular/cli": "^7.2.1", "@angular/cli": "^7.2.1",
"@angular/compiler-cli": "~8.0.3", "@angular/compiler-cli": "~8.0.3",
"@angular/language-service": "~8.0.3", "@angular/language-service": "~8.0.3",
"@angularclass/hmr": "^2.1.3",
"@types/jasmine": "~2.8.8", "@types/jasmine": "~2.8.8",
"@types/jasminewd2": "~2.0.4", "@types/jasminewd2": "~2.0.4",
"@types/node": "~10.12.18", "@types/node": "~10.12.18",
...@@ -88,7 +90,7 @@ ...@@ -88,7 +90,7 @@
}, },
"husky": { "husky": {
"hooks": { "hooks": {
"pre-commit": ".githooks/pre-commit && pretty-quick --staged --bail --pattern '**/*.*(ts|html|scss)'" "pre-commit": "sh .githooks/pre-commit && pretty-quick --staged --bail --pattern \"**/*.*(ts|html|scss)\""
} }
} }
} }
...@@ -35,8 +35,6 @@ export class Minds { ...@@ -35,8 +35,6 @@ export class Minds {
showTOSModal: boolean = false; showTOSModal: boolean = false;
paramsSubscription;
protected router$: Subscription; protected router$: Subscription;
constructor( constructor(
...@@ -125,7 +123,6 @@ export class Minds { ...@@ -125,7 +123,6 @@ export class Minds {
ngOnDestroy() { ngOnDestroy() {
this.loginReferrer.unlisten(); this.loginReferrer.unlisten();
this.scrollToTop.unlisten(); this.scrollToTop.unlisten();
this.paramsSubscription.unsubscribe();
} }
@HostBinding('class') get cssColorSchemeOverride() { @HostBinding('class') get cssColorSchemeOverride() {
......
...@@ -60,4 +60,9 @@ ...@@ -60,4 +60,9 @@
border-color: themed($m-blue); border-color: themed($m-blue);
} }
} }
&[disabled] {
cursor: default;
opacity: 0.6;
}
} }
...@@ -128,11 +128,11 @@ describe('LoginComponent', () => { ...@@ -128,11 +128,11 @@ describe('LoginComponent', () => {
it('should redirect after registering', () => { it('should redirect after registering', () => {
comp.registered(); comp.registered();
expect(signupModalServiceMock.setDisplay).toHaveBeenCalled(); // expect(signupModalServiceMock.setDisplay).toHaveBeenCalled();
expect(signupModalServiceMock.setDisplay.calls.mostRecent().args[0]).toBe( // expect(signupModalServiceMock.setDisplay.calls.mostRecent().args[0]).toBe(
'categories' // 'categories'
); // );
expect(signupModalServiceMock.open).toHaveBeenCalled(); // expect(signupModalServiceMock.open).toHaveBeenCalled();
expect(loginReferrerServiceMock.navigate).toHaveBeenCalled(); expect(loginReferrerServiceMock.navigate).toHaveBeenCalled();
expect( expect(
loginReferrerServiceMock.navigate.calls.mostRecent().args[0] loginReferrerServiceMock.navigate.calls.mostRecent().args[0]
......
...@@ -73,7 +73,6 @@ export class LoginComponent { ...@@ -73,7 +73,6 @@ export class LoginComponent {
registered() { registered() {
if (this.redirectTo) this.navigateToRedirection(); if (this.redirectTo) this.navigateToRedirection();
else { else {
this.modal.setDisplay('categories').open();
this.loginReferrer.navigate({ this.loginReferrer.navigate({
defaultUrl: '/' + this.session.getLoggedInUser().username, defaultUrl: '/' + this.session.getLoggedInUser().username,
}); });
......
...@@ -263,7 +263,7 @@ ...@@ -263,7 +263,7 @@
</button> </button>
</div> </div>
<ng-container *mIfFeature="'pro'"> <ng-container *mIfFeature="'purchase-pro'">
<a <a
*ngIf="showBecomeProButton" *ngIf="showBecomeProButton"
class="m-btn m-link-btn m-btn--with-icon m-btn--slim m-btn--action" class="m-btn m-link-btn m-btn--with-icon m-btn--slim m-btn--action"
......
...@@ -146,6 +146,7 @@ describe('ChannelSidebar', () => { ...@@ -146,6 +146,7 @@ describe('ChannelSidebar', () => {
featuresServiceMock.mock('es-feeds', false); featuresServiceMock.mock('es-feeds', false);
featuresServiceMock.mock('permissions', true); featuresServiceMock.mock('permissions', true);
featuresServiceMock.mock('pro', true); featuresServiceMock.mock('pro', true);
featuresServiceMock.mock('purchase-pro', true);
clientMock.response = {}; clientMock.response = {};
uploadMock.response = {}; uploadMock.response = {};
comp = fixture.componentInstance; comp = fixture.componentInstance;
......
...@@ -36,6 +36,12 @@ export class ChannelSubscribers { ...@@ -36,6 +36,12 @@ export class ChannelSubscribers {
return; return;
} }
if (response['load-next']) {
this.offset = response['load-next'];
} else {
this.moreData = false;
}
this.users = this.users.concat(response.users); this.users = this.users.concat(response.users);
this.offset = response['load-next']; this.offset = response['load-next'];
......
...@@ -38,6 +38,12 @@ export class ChannelSubscriptions { ...@@ -38,6 +38,12 @@ export class ChannelSubscriptions {
return; return;
} }
if (response['load-next']) {
this.offset = response['load-next'];
} else {
this.moreData = false;
}
this.users = this.users.concat(response.users); this.users = this.users.concat(response.users);
this.offset = response['load-next']; this.offset = response['load-next'];
......
import { EventEmitter } from '@angular/core'; import { EventEmitter, Injectable } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router'; import { Router, NavigationEnd } from '@angular/router';
import { ScrollService } from '../../../services/ux/scroll'; import { ScrollService } from '../../../services/ux/scroll';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
@Injectable()
export class SignupModalService { export class SignupModalService {
defaultSubtitle: string = defaultSubtitle: string =
'Signup to comment, upload, vote and earn 100+ free views on your content daily.'; 'Signup to comment, upload, vote and earn 100+ free views on your content daily.';
......
import { Component } from '@angular/core'; import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router'; import { NavigationEnd, Router } from '@angular/router';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { Session } from '../../../services/session'; import { Session } from '../../../services/session';
import { ScrollService } from '../../../services/ux/scroll'; import { ScrollService } from '../../../services/ux/scroll';
import { SignupModal } from './signup';
import { Storage } from '../../../services/storage';
@Component({ @Component({
selector: 'm-modal-signup-on-scroll', selector: 'm-modal-signup-on-scroll',
template: ` template: `
<m-modal-signup open="true" *ngIf="open"></m-modal-signup> <m-modal-signup (onClose)="onModalClosed()" #modal></m-modal-signup>
`, `,
}) })
export class SignupOnScrollModal { export class SignupOnScrollModal implements OnInit, OnDestroy {
open: boolean = false; open: boolean = false;
route: string = ''; route: string = '';
scroll_listener; scroll_listener;
...@@ -21,10 +23,13 @@ export class SignupOnScrollModal { ...@@ -21,10 +23,13 @@ export class SignupOnScrollModal {
routerSubscription: Subscription; routerSubscription: Subscription;
@ViewChild('modal', { static: true }) modal: SignupModal;
constructor( constructor(
public session: Session, public session: Session,
public router: Router, public router: Router,
public scroll: ScrollService public scroll: ScrollService,
private storage: Storage
) {} ) {}
ngOnInit() { ngOnInit() {
...@@ -66,9 +71,13 @@ export class SignupOnScrollModal { ...@@ -66,9 +71,13 @@ export class SignupOnScrollModal {
default: default:
this.scroll_listener = this.scroll.listen(e => { this.scroll_listener = this.scroll.listen(e => {
if (this.scroll.view.scrollTop > 20) { if (this.scroll.view.scrollTop > 20) {
if (window.localStorage.getItem('hideSignupModal')) if (window.localStorage.getItem('hideSignupModal')) {
this.open = false; this.open = false;
else this.open = true; this.modal.open = false;
} else {
this.open = true;
this.modal.open = true;
}
} }
}, 100); }, 100);
} }
...@@ -90,4 +99,11 @@ export class SignupOnScrollModal { ...@@ -90,4 +99,11 @@ export class SignupOnScrollModal {
this.scroll.unListen(this.scroll_listener); this.scroll.unListen(this.scroll_listener);
} }
} }
onModalClosed() {
if (this.open) {
this.storage.set('hideSignupModal', '1');
this.open = false;
}
}
} }
...@@ -7,10 +7,7 @@ ...@@ -7,10 +7,7 @@
class="mdl-card__title" class="mdl-card__title"
[hidden]="display == 'onboarding' || display == 'categories'" [hidden]="display == 'onboarding' || display == 'categories'"
> >
<img <img [src]="logo" (click)="close()" />
src="{{ minds.cdn_assets_url }}assets/logos/logo.svg"
(click)="close()"
/>
</div> </div>
<!-- Initial Display --> <!-- Initial Display -->
...@@ -77,11 +74,6 @@ ...@@ -77,11 +74,6 @@
(canceled)="close()" (canceled)="close()"
*ngIf="display == 'fb-complete'" *ngIf="display == 'fb-complete'"
></minds-form-fb-register> ></minds-form-fb-register>
<!-- Categories selector -->
<minds-onboarding-categories-selector
(done)="done('categories')"
*ngIf="display == 'categories'"
></minds-onboarding-categories-selector>
<!-- Tutorial Display --> <!-- Tutorial Display -->
<minds-tutorial *ngIf="display == 'tutorial'"></minds-tutorial> <minds-tutorial *ngIf="display == 'tutorial'"></minds-tutorial>
</m-modal> </m-modal>
...@@ -3,6 +3,8 @@ import { ...@@ -3,6 +3,8 @@ import {
ChangeDetectorRef, ChangeDetectorRef,
NgZone, NgZone,
ApplicationRef, ApplicationRef,
Output,
EventEmitter,
} from '@angular/core'; } from '@angular/core';
import { Location } from '@angular/common'; import { Location } from '@angular/common';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
...@@ -11,6 +13,7 @@ import { SignupModalService } from './service'; ...@@ -11,6 +13,7 @@ import { SignupModalService } from './service';
import { Session } from '../../../services/session'; import { Session } from '../../../services/session';
import { AnalyticsService } from '../../../services/analytics'; import { AnalyticsService } from '../../../services/analytics';
import { LoginReferrerService } from '../../../services/login-referrer.service'; import { LoginReferrerService } from '../../../services/login-referrer.service';
import { SiteService } from '../../../common/services/site.service';
@Component({ @Component({
selector: 'm-modal-signup', selector: 'm-modal-signup',
...@@ -18,6 +21,7 @@ import { LoginReferrerService } from '../../../services/login-referrer.service'; ...@@ -18,6 +21,7 @@ import { LoginReferrerService } from '../../../services/login-referrer.service';
templateUrl: 'signup.html', templateUrl: 'signup.html',
}) })
export class SignupModal { export class SignupModal {
@Output('onClose') onClosed: EventEmitter<any> = new EventEmitter<any>();
open: boolean = false; open: boolean = false;
route: string = ''; route: string = '';
minds = window.Minds; minds = window.Minds;
...@@ -27,6 +31,12 @@ export class SignupModal { ...@@ -27,6 +31,12 @@ export class SignupModal {
display: string = 'initial'; display: string = 'initial';
overrideOnboarding: boolean = false; overrideOnboarding: boolean = false;
get logo() {
return this.site.isProDomain
? `${this.minds.cdn_url}fs/v1/thumbnail/${this.site.pro.logo_guid}/master`
: `${this.minds.cdn_assets_url}assets/logos/logo.svg`;
}
constructor( constructor(
public session: Session, public session: Session,
private router: Router, private router: Router,
...@@ -36,13 +46,14 @@ export class SignupModal { ...@@ -36,13 +46,14 @@ export class SignupModal {
private zone: NgZone, private zone: NgZone,
private applicationRef: ApplicationRef, private applicationRef: ApplicationRef,
private loginReferrer: LoginReferrerService, private loginReferrer: LoginReferrerService,
private analyticsService: AnalyticsService private analyticsService: AnalyticsService,
private site: SiteService
) { ) {
this.listen(); this.listen();
this.service.isOpen.subscribe({ this.service.isOpen.subscribe({
next: open => { next: open => {
this.open = open; this.open = open;
//hack: nasty ios work around // hack: nasty ios work around
this.applicationRef.tick(); this.applicationRef.tick();
this.listen(); this.listen();
}, },
...@@ -66,6 +77,7 @@ export class SignupModal { ...@@ -66,6 +77,7 @@ export class SignupModal {
break; break;
default: default:
this.service.close(); this.service.close();
this.onClosed.emit();
} }
} }
...@@ -120,9 +132,6 @@ export class SignupModal { ...@@ -120,9 +132,6 @@ export class SignupModal {
'toolbar=no, location=no, directories=no, status=no, menubar=no, copyhistory=no, width=600, height=400, top=100, left=100' 'toolbar=no, location=no, directories=no, status=no, menubar=no, copyhistory=no, width=600, height=400, top=100, left=100'
); );
break; break;
case 'categories':
this.display = 'tutorial';
break;
} }
} }
...@@ -153,10 +162,6 @@ export class SignupModal { ...@@ -153,10 +162,6 @@ export class SignupModal {
}); });
this.display = 'fb-username'; this.display = 'fb-username';
break; break;
case 'categories':
this.display = 'initial';
this.close();
break;
case 'tutorial': case 'tutorial':
this.display = 'initial'; this.display = 'initial';
this.close(); this.close();
...@@ -166,6 +171,7 @@ export class SignupModal { ...@@ -166,6 +171,7 @@ export class SignupModal {
onClose(e: boolean) { onClose(e: boolean) {
this.service.close(); this.service.close();
this.onClosed.emit();
if ( if (
this.display === 'login' || this.display === 'login' ||
this.display === 'register' || this.display === 'register' ||
......
...@@ -116,6 +116,6 @@ export class NotificationService { ...@@ -116,6 +116,6 @@ export class NotificationService {
} }
ngOnDestroy() { ngOnDestroy() {
this.notificationPollTimer.unsubscribe(); this.updateNotificationCountSubscription.unsubscribe();
} }
} }
...@@ -3,6 +3,8 @@ import { Client } from '../../services/api/client'; ...@@ -3,6 +3,8 @@ import { Client } from '../../services/api/client';
@Injectable() @Injectable()
export class PlusService { export class PlusService {
protected cachedResponse: any;
constructor(protected client: Client) {} constructor(protected client: Client) {}
async isActive(): Promise<boolean> { async isActive(): Promise<boolean> {
...@@ -12,9 +14,19 @@ export class PlusService { ...@@ -12,9 +14,19 @@ export class PlusService {
throw new Error('Unable to check your Plus status'); throw new Error('Unable to check your Plus status');
} }
this.cachedResponse = result;
return Boolean(result.active); return Boolean(result.active);
} }
async canBeCancelled(): Promise<boolean> {
if (!this.cachedResponse) {
await this.isActive();
}
return Boolean(this.cachedResponse.can_be_cancelled);
}
async disable(): Promise<boolean> { async disable(): Promise<boolean> {
await this.client.delete('api/v1/plus/subscription'); await this.client.delete('api/v1/plus/subscription');
return true; return true;
......
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
<div> <div>
<button <button
class="mf-button mf-button--destructive" class="mf-button mf-button--destructive"
[disabled]="inProgress || criticalError" [disabled]="!canBeCancelled || inProgress || criticalError"
(click)="disable()" (click)="disable()"
i18n i18n
> >
......
...@@ -43,6 +43,8 @@ export class PlusSubscriptionComponent implements OnInit { ...@@ -43,6 +43,8 @@ export class PlusSubscriptionComponent implements OnInit {
active: boolean; active: boolean;
canBeCancelled: boolean;
criticalError: boolean = false; criticalError: boolean = false;
error: string = ''; error: string = '';
...@@ -85,6 +87,7 @@ export class PlusSubscriptionComponent implements OnInit { ...@@ -85,6 +87,7 @@ export class PlusSubscriptionComponent implements OnInit {
try { try {
this.active = await this.service.isActive(); this.active = await this.service.isActive();
this.canBeCancelled = await this.service.canBeCancelled();
} catch (e) { } catch (e) {
this.criticalError = true; this.criticalError = true;
this.error = (e && e.message) || 'Unknown error'; this.error = (e && e.message) || 'Unknown error';
......
...@@ -124,3 +124,4 @@ ...@@ -124,3 +124,4 @@
</div> </div>
<m-overlay-modal #overlayModal></m-overlay-modal> <m-overlay-modal #overlayModal></m-overlay-modal>
<m-modal-signup-on-scroll></m-modal-signup-on-scroll>