...
 
Commits (20)
......@@ -49,6 +49,14 @@
"with": "src/environments/environment.prod.ts"
}
]
},
"hmr": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.hmr.ts"
}
]
}
}
},
......@@ -60,6 +68,10 @@
"configurations": {
"production": {
"browserTarget": "v5.x:build:production"
},
"hmr": {
"hmr": true,
"browserTarget": "v5.x:build:hmr"
}
}
},
......
......@@ -1401,6 +1401,12 @@
"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": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
......@@ -5787,6 +5793,11 @@
"integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=",
"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": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
......
......@@ -10,6 +10,7 @@
"build": "ng build --prod",
"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",
"serve-dev": "ng serve --host=0.0.0.0 --deploy-url=/en/ --configuration=hmr --hmr --poll=800 --progress",
"test": "ng test",
"lint": "ng lint",
"e2e": "cypress run --debug",
......@@ -57,6 +58,7 @@
"@angular/cli": "^7.2.1",
"@angular/compiler-cli": "~8.0.3",
"@angular/language-service": "~8.0.3",
"@angularclass/hmr": "^2.1.3",
"@types/jasmine": "~2.8.8",
"@types/jasminewd2": "~2.0.4",
"@types/node": "~10.12.18",
......@@ -88,7 +90,7 @@
},
"husky": {
"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 {
showTOSModal: boolean = false;
paramsSubscription;
protected router$: Subscription;
constructor(
......@@ -125,7 +123,6 @@ export class Minds {
ngOnDestroy() {
this.loginReferrer.unlisten();
this.scrollToTop.unlisten();
this.paramsSubscription.unsubscribe();
}
@HostBinding('class') get cssColorSchemeOverride() {
......
......@@ -60,4 +60,9 @@
border-color: themed($m-blue);
}
}
&[disabled] {
cursor: default;
opacity: 0.6;
}
}
......@@ -128,11 +128,11 @@ describe('LoginComponent', () => {
it('should redirect after registering', () => {
comp.registered();
expect(signupModalServiceMock.setDisplay).toHaveBeenCalled();
expect(signupModalServiceMock.setDisplay.calls.mostRecent().args[0]).toBe(
'categories'
);
expect(signupModalServiceMock.open).toHaveBeenCalled();
// expect(signupModalServiceMock.setDisplay).toHaveBeenCalled();
// expect(signupModalServiceMock.setDisplay.calls.mostRecent().args[0]).toBe(
// 'categories'
// );
// expect(signupModalServiceMock.open).toHaveBeenCalled();
expect(loginReferrerServiceMock.navigate).toHaveBeenCalled();
expect(
loginReferrerServiceMock.navigate.calls.mostRecent().args[0]
......
......@@ -73,7 +73,6 @@ export class LoginComponent {
registered() {
if (this.redirectTo) this.navigateToRedirection();
else {
this.modal.setDisplay('categories').open();
this.loginReferrer.navigate({
defaultUrl: '/' + this.session.getLoggedInUser().username,
});
......
......@@ -263,7 +263,7 @@
</button>
</div>
<ng-container *mIfFeature="'pro'">
<ng-container *mIfFeature="'purchase-pro'">
<a
*ngIf="showBecomeProButton"
class="m-btn m-link-btn m-btn--with-icon m-btn--slim m-btn--action"
......
......@@ -146,6 +146,7 @@ describe('ChannelSidebar', () => {
featuresServiceMock.mock('es-feeds', false);
featuresServiceMock.mock('permissions', true);
featuresServiceMock.mock('pro', true);
featuresServiceMock.mock('purchase-pro', true);
clientMock.response = {};
uploadMock.response = {};
comp = fixture.componentInstance;
......
......@@ -36,6 +36,12 @@ export class ChannelSubscribers {
return;
}
if (response['load-next']) {
this.offset = response['load-next'];
} else {
this.moreData = false;
}
this.users = this.users.concat(response.users);
this.offset = response['load-next'];
......
......@@ -38,6 +38,12 @@ export class ChannelSubscriptions {
return;
}
if (response['load-next']) {
this.offset = response['load-next'];
} else {
this.moreData = false;
}
this.users = this.users.concat(response.users);
this.offset = response['load-next'];
......
import { EventEmitter } from '@angular/core';
import { EventEmitter, Injectable } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import { ScrollService } from '../../../services/ux/scroll';
import { Subscription } from 'rxjs';
@Injectable()
export class SignupModalService {
defaultSubtitle: string =
'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 { Subscription } from 'rxjs';
import { Session } from '../../../services/session';
import { ScrollService } from '../../../services/ux/scroll';
import { SignupModal } from './signup';
import { Storage } from '../../../services/storage';
@Component({
selector: 'm-modal-signup-on-scroll',
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;
route: string = '';
scroll_listener;
......@@ -21,10 +23,13 @@ export class SignupOnScrollModal {
routerSubscription: Subscription;
@ViewChild('modal', { static: true }) modal: SignupModal;
constructor(
public session: Session,
public router: Router,
public scroll: ScrollService
public scroll: ScrollService,
private storage: Storage
) {}
ngOnInit() {
......@@ -66,9 +71,13 @@ export class SignupOnScrollModal {
default:
this.scroll_listener = this.scroll.listen(e => {
if (this.scroll.view.scrollTop > 20) {
if (window.localStorage.getItem('hideSignupModal'))
if (window.localStorage.getItem('hideSignupModal')) {
this.open = false;
else this.open = true;
this.modal.open = false;
} else {
this.open = true;
this.modal.open = true;
}
}
}, 100);
}
......@@ -90,4 +99,11 @@ export class SignupOnScrollModal {
this.scroll.unListen(this.scroll_listener);
}
}
onModalClosed() {
if (this.open) {
this.storage.set('hideSignupModal', '1');
this.open = false;
}
}
}
......@@ -7,10 +7,7 @@
class="mdl-card__title"
[hidden]="display == 'onboarding' || display == 'categories'"
>
<img
src="{{ minds.cdn_assets_url }}assets/logos/logo.svg"
(click)="close()"
/>
<img [src]="logo" (click)="close()" />
</div>
<!-- Initial Display -->
......@@ -77,11 +74,6 @@
(canceled)="close()"
*ngIf="display == 'fb-complete'"
></minds-form-fb-register>
<!-- Categories selector -->
<minds-onboarding-categories-selector
(done)="done('categories')"
*ngIf="display == 'categories'"
></minds-onboarding-categories-selector>
<!-- Tutorial Display -->
<minds-tutorial *ngIf="display == 'tutorial'"></minds-tutorial>
</m-modal>
......@@ -3,6 +3,8 @@ import {
ChangeDetectorRef,
NgZone,
ApplicationRef,
Output,
EventEmitter,
} from '@angular/core';
import { Location } from '@angular/common';
import { Router } from '@angular/router';
......@@ -11,6 +13,7 @@ import { SignupModalService } from './service';
import { Session } from '../../../services/session';
import { AnalyticsService } from '../../../services/analytics';
import { LoginReferrerService } from '../../../services/login-referrer.service';
import { SiteService } from '../../../common/services/site.service';
@Component({
selector: 'm-modal-signup',
......@@ -18,6 +21,7 @@ import { LoginReferrerService } from '../../../services/login-referrer.service';
templateUrl: 'signup.html',
})
export class SignupModal {
@Output('onClose') onClosed: EventEmitter<any> = new EventEmitter<any>();
open: boolean = false;
route: string = '';
minds = window.Minds;
......@@ -27,6 +31,12 @@ export class SignupModal {
display: string = 'initial';
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(
public session: Session,
private router: Router,
......@@ -36,13 +46,14 @@ export class SignupModal {
private zone: NgZone,
private applicationRef: ApplicationRef,
private loginReferrer: LoginReferrerService,
private analyticsService: AnalyticsService
private analyticsService: AnalyticsService,
private site: SiteService
) {
this.listen();
this.service.isOpen.subscribe({
next: open => {
this.open = open;
//hack: nasty ios work around
// hack: nasty ios work around
this.applicationRef.tick();
this.listen();
},
......@@ -66,6 +77,7 @@ export class SignupModal {
break;
default:
this.service.close();
this.onClosed.emit();
}
}
......@@ -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'
);
break;
case 'categories':
this.display = 'tutorial';
break;
}
}
......@@ -153,10 +162,6 @@ export class SignupModal {
});
this.display = 'fb-username';
break;
case 'categories':
this.display = 'initial';
this.close();
break;
case 'tutorial':
this.display = 'initial';
this.close();
......@@ -166,6 +171,7 @@ export class SignupModal {
onClose(e: boolean) {
this.service.close();
this.onClosed.emit();
if (
this.display === 'login' ||
this.display === 'register' ||
......
......@@ -116,6 +116,6 @@ export class NotificationService {
}
ngOnDestroy() {
this.notificationPollTimer.unsubscribe();
this.updateNotificationCountSubscription.unsubscribe();
}
}
......@@ -3,6 +3,8 @@ import { Client } from '../../services/api/client';
@Injectable()
export class PlusService {
protected cachedResponse: any;
constructor(protected client: Client) {}
async isActive(): Promise<boolean> {
......@@ -12,9 +14,19 @@ export class PlusService {
throw new Error('Unable to check your Plus status');
}
this.cachedResponse = result;
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> {
await this.client.delete('api/v1/plus/subscription');
return true;
......
......@@ -56,7 +56,7 @@
<div>
<button
class="mf-button mf-button--destructive"
[disabled]="inProgress || criticalError"
[disabled]="!canBeCancelled || inProgress || criticalError"
(click)="disable()"
i18n
>
......
......@@ -43,6 +43,8 @@ export class PlusSubscriptionComponent implements OnInit {
active: boolean;
canBeCancelled: boolean;
criticalError: boolean = false;
error: string = '';
......@@ -85,6 +87,7 @@ export class PlusSubscriptionComponent implements OnInit {
try {
this.active = await this.service.isActive();
this.canBeCancelled = await this.service.canBeCancelled();
} catch (e) {
this.criticalError = true;
this.error = (e && e.message) || 'Unknown error';
......
......@@ -124,3 +124,4 @@
</div>
<m-overlay-modal #overlayModal></m-overlay-modal>
<m-modal-signup-on-scroll></m-modal-signup-on-scroll>
......@@ -60,6 +60,21 @@ m-pro--channel {
minds-button-boost {
display: none !important;
}
m-modal-signup {
m-modal {
z-index: 9999999;
.m-modal-container .mdl-card {
background-color: var(--m-pro--transparent-background-color);
color: var(--m-pro--text-color);
.m-modal-signup-apps {
display: none;
}
}
}
}
}
@media screen and (max-width: $max-mobile) {
......
......@@ -25,7 +25,7 @@ import { SessionsStorageService } from '../../../services/session-storage.servic
import { SiteService } from '../../../common/services/site.service';
@Component({
providers: [ProChannelService, OverlayModalService],
providers: [ProChannelService, OverlayModalService, SignupModalService],
selector: 'm-pro--channel',
templateUrl: 'channel.component.html',
changeDetection: ChangeDetectionStrategy.Default,
......
......@@ -59,9 +59,10 @@ export class ProChannelListComponent implements OnInit, OnDestroy {
return elements.filter((element: BehaviorSubject<any>) => {
const entity = element.getValue();
return (
!!entity.thumbnail_src ||
!!entity.custom_data ||
(entity.thumbnails && entity.thumbnails.length > 0)
entity.type === 'group' ||
(!!entity.thumbnail_src ||
!!entity.custom_data ||
(entity.thumbnails && entity.thumbnails.length > 0))
);
});
})
......
......@@ -27,10 +27,6 @@
<img *ngSwitchDefault [src]="entity.thumbnail_src" #img />
</div>
<div
class="m-proChannelTile__text"
(click)="tileClicked()"
*ngIf="getTitle() || getText()"
>
<div class="m-proChannelTile__text" (click)="tileClicked()" *ngIf="getTitle()">
<h2 [title]="getTitle()">{{ getTitle() }}</h2>
</div>
......@@ -50,6 +50,12 @@ export class ProTileComponent {
return this.entity.title && this.entity.title.trim() !== ''
? this.entity.title
: this.entity.message;
case 'activity':
return this.entity.title && this.entity.title.trim() !== ''
? this.entity.title
: this.entity.blurb
? this.entity.blurb
: this.entity.message;
default:
return '';
}
......@@ -62,6 +68,8 @@ export class ProTileComponent {
case 'object:image':
case 'object:video':
return this.entity.description;
case 'activity':
return this.entity.blurb ? this.entity.blurb : this.entity.message;
default:
return '';
}
......
......@@ -34,6 +34,7 @@ import { MediaEditComponent } from '../media/edit/edit.component';
import { BlogViewInfinite } from '../blogs/view/infinite';
import { BlogEdit } from '../blogs/edit/edit';
import { CanDeactivateGuardService } from '../../services/can-deactivate-guard';
import { ModalsModule } from '../modals/modals.module';
const routes: Routes = [
{
......@@ -140,6 +141,7 @@ export const PRO_DOMAIN_ROUTES = [
WireModule,
VideoModule,
AuthModule,
ModalsModule,
],
providers: [ProService],
declarations: [
......
export const environment = {
production: false,
version: 'VERSION',
hmr: true,
};
export const environment = {
production: true,
version: 'VERSION',
hmr: false,
};
......@@ -6,4 +6,5 @@
export const environment = {
production: false,
version: 'VERSION',
hmr: false,
};
import { NgModuleRef, ApplicationRef } from '@angular/core';
import { createNewHosts } from '@angularclass/hmr';
export const hmrBootstrap = (
module: any,
bootstrap: () => Promise<NgModuleRef<any>>
) => {
let ngModule: NgModuleRef<any>;
module.hot.accept();
bootstrap().then(mod => (ngModule = mod));
module.hot.dispose(() => {
const appRef: ApplicationRef = ngModule.injector.get(ApplicationRef);
const elements = appRef.components.map(c => c.location.nativeElement);
const makeVisible = createNewHosts(elements);
ngModule.destroy();
makeVisible();
});
};
......@@ -3,9 +3,21 @@ import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { MindsModule } from './app/app.module';
import { environment } from './environments/environment';
import { hmrBootstrap } from './hmr';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(MindsModule);
const bootstrap = () => platformBrowserDynamic().bootstrapModule(MindsModule);
if (environment.hmr) {
if (module['hot']) {
hmrBootstrap(module, bootstrap);
} else {
console.error('HMR is not enabled for webpack-dev-server!');
console.log('Are you using the --hmr flag for ng serve?');
}
} else {
bootstrap().catch(err => console.log(err));
}
......@@ -4,7 +4,7 @@
"outDir": "../out-tsc/app",
"baseUrl": "./",
"module": "es2015",
"types": []
"types": ["node"]
},
"exclude": [
"test.ts",
......