premium and paid org callouts
This commit is contained in:
parent
1f6dd079cd
commit
1cee1c6e8f
|
@ -101,7 +101,24 @@ export class AppComponent implements OnDestroy, OnInit {
|
|||
break;
|
||||
case 'syncCompleted':
|
||||
break;
|
||||
case 'upgradeOrganization':
|
||||
const upgradeConfirmed = await this.platformUtilsService.showDialog(
|
||||
this.i18nService.t('upgradeOrganizationDesc'), this.i18nService.t('upgradeOrganization'),
|
||||
this.i18nService.t('upgradeOrganization'), this.i18nService.t('cancel'));
|
||||
if (upgradeConfirmed) {
|
||||
this.router.navigate(['organizations', message.organizationId, 'settings', 'billing']);
|
||||
}
|
||||
break;
|
||||
case 'premiumRequired':
|
||||
const premiumConfirmed = await this.platformUtilsService.showDialog(
|
||||
this.i18nService.t('premiumRequiredDesc'), this.i18nService.t('premiumRequired'),
|
||||
this.i18nService.t('learnMore'), this.i18nService.t('cancel'));
|
||||
if (premiumConfirmed) {
|
||||
this.router.navigate(['settings/premium']);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -11,6 +11,7 @@ import { AuditService } from 'jslib/abstractions/audit.service';
|
|||
import { CipherService } from 'jslib/abstractions/cipher.service';
|
||||
import { FolderService } from 'jslib/abstractions/folder.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { StateService } from 'jslib/abstractions/state.service';
|
||||
|
@ -36,9 +37,11 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit {
|
|||
analytics: Angulartics2, toasterService: ToasterService,
|
||||
auditService: AuditService, stateService: StateService,
|
||||
tokenService: TokenService, totpService: TotpService,
|
||||
passwordGenerationService: PasswordGenerationService, private apiService: ApiService) {
|
||||
passwordGenerationService: PasswordGenerationService, private apiService: ApiService,
|
||||
messagingService: MessagingService) {
|
||||
super(cipherService, folderService, i18nService, platformUtilsService, analytics,
|
||||
toasterService, auditService, stateService, tokenService, totpService, passwordGenerationService);
|
||||
toasterService, auditService, stateService, tokenService, totpService, passwordGenerationService,
|
||||
messagingService);
|
||||
}
|
||||
|
||||
protected async loadCipher() {
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
} from '@angular/router';
|
||||
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { SyncService } from 'jslib/abstractions/sync.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
|
@ -50,7 +51,7 @@ export class VaultComponent implements OnInit {
|
|||
constructor(private route: ActivatedRoute, private userService: UserService,
|
||||
private location: Location, private router: Router,
|
||||
private syncService: SyncService, private i18nService: I18nService,
|
||||
private componentFactoryResolver: ComponentFactoryResolver) { }
|
||||
private componentFactoryResolver: ComponentFactoryResolver, private messagingService: MessagingService) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.route.parent.params.subscribe(async (params) => {
|
||||
|
@ -139,6 +140,11 @@ export class VaultComponent implements OnInit {
|
|||
}
|
||||
|
||||
editCipherAttachments(cipher: CipherView) {
|
||||
if (this.organization.maxStorageGb == null || this.organization.maxStorageGb === 0) {
|
||||
this.messagingService.send('upgradeOrganization', { organizationId: cipher.organizationId });
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.modal != null) {
|
||||
this.modal.close();
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
<h3 class="mb-0">
|
||||
{{p.name}}
|
||||
<i class="fa fa-check text-success fa-fw" *ngIf="p.enabled" title="{{'enabled' | i18n}}"></i>
|
||||
<a href="#" appStopClick class="badge badge-primary" *ngIf="!premium && p.premium">
|
||||
<a href="#" appStopClick class="badge badge-primary" *ngIf="!premium && p.premium" (click)="premiumRequired()">
|
||||
{{'premium' | i18n}}
|
||||
</a>
|
||||
</h3>
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
} from '@angular/core';
|
||||
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { TokenService } from 'jslib/abstractions/token.service';
|
||||
|
||||
import { TwoFactorProviders } from 'jslib/services/auth.service';
|
||||
|
@ -42,7 +43,7 @@ export class TwoFactorSetupComponent implements OnInit {
|
|||
private modal: ModalComponent = null;
|
||||
|
||||
constructor(private apiService: ApiService, private tokenService: TokenService,
|
||||
private componentFactoryResolver: ComponentFactoryResolver) { }
|
||||
private componentFactoryResolver: ComponentFactoryResolver, private messagingService: MessagingService) { }
|
||||
|
||||
async ngOnInit() {
|
||||
this.premium = this.tokenService.getPremium();
|
||||
|
@ -125,6 +126,14 @@ export class TwoFactorSetupComponent implements OnInit {
|
|||
this.openModal(this.recoveryModalRef, TwoFactorRecoveryComponent);
|
||||
}
|
||||
|
||||
async premiumRequired() {
|
||||
const premium = await this.tokenService.getPremium();
|
||||
if (!premium) {
|
||||
this.messagingService.send('premiumRequired');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private openModal<T>(ref: ViewContainerRef, type: Type<T>): T {
|
||||
if (this.modal != null) {
|
||||
this.modal.close();
|
||||
|
|
|
@ -50,8 +50,7 @@
|
|||
<a href="#" class="d-block mr-2" appStopClick title="{{'generatePassword' | i18n}}" (click)="generatePassword()">
|
||||
<i class="fa fa-lg fa-fw fa-refresh"></i>
|
||||
</a>
|
||||
<a href="#" class="d-block" #checkPasswordBtn appStopClick title="{{'checkPassword' | i18n}}" (click)="checkPassword()"
|
||||
[appApiAction]="checkPasswordPromise">
|
||||
<a href="#" class="d-block" #checkPasswordBtn appStopClick title="{{'checkPassword' | i18n}}" (click)="checkPassword()" [appApiAction]="checkPasswordPromise">
|
||||
<i class="fa fa-lg fa-fw fa-check-circle" [hidden]="checkPasswordBtn.loading"></i>
|
||||
<i class="fa fa-lg fa-fw fa-spinner fa-spin" [hidden]="!checkPasswordBtn.loading" title="{{'loading' | i18n}}"></i>
|
||||
</a>
|
||||
|
@ -81,6 +80,12 @@
|
|||
<div class="col-6 form-group totp d-flex align-items-end" [ngClass]="{'low': totpLow}">
|
||||
<div *ngIf="!cipher.login.totp || !totpCode">
|
||||
<img src="../../images/totp-countdown.png" title="{{'verificationCodeTotp' | i18n}}" class="ml-2">
|
||||
<a href="#" appStopClick class="badge badge-primary ml-3" (click)="premiumRequired()" *ngIf="!cipher.organizationId && !isPremium">
|
||||
{{'premium' | i18n}}
|
||||
</a>
|
||||
<a href="#" appStopClick class="badge badge-primary ml-3" (click)="upgradeOrganization()" *ngIf="cipher.organizationId && !organizationUseTotp">
|
||||
{{'upgrade' | i18n}}
|
||||
</a>
|
||||
</div>
|
||||
<div *ngIf="cipher.login.totp && totpCode" class="d-flex align-items-center">
|
||||
<span class="totp-countdown mr-3 ml-2">
|
||||
|
@ -364,8 +369,8 @@
|
|||
<button *ngIf="!organization" type="button" (click)="toggleFavorite()" class="btn btn-link" title="{{(cipher.favorite ? 'unfavorite' : 'favorite') | i18n}}">
|
||||
<i class="fa fa-lg" [ngClass]="{'fa-star': cipher.favorite, 'fa-star-o': !cipher.favorite}"></i>
|
||||
</button>
|
||||
<button #deleteBtn type="button" (click)="delete()" class="btn btn-outline-danger" title="{{'delete' | i18n}}"
|
||||
*ngIf="editMode" [disabled]="deleteBtn.loading" [appApiAction]="deletePromise">
|
||||
<button #deleteBtn type="button" (click)="delete()" class="btn btn-outline-danger" title="{{'delete' | i18n}}" *ngIf="editMode"
|
||||
[disabled]="deleteBtn.loading" [appApiAction]="deletePromise">
|
||||
<i class="fa fa-trash-o fa-lg fa-fw" [hidden]="deleteBtn.loading"></i>
|
||||
<i class="fa fa-spinner fa-spin fa-lg fa-fw" [hidden]="!deleteBtn.loading" title="{{'loading' | i18n}}"></i>
|
||||
</button>
|
||||
|
|
|
@ -12,6 +12,7 @@ import { AuditService } from 'jslib/abstractions/audit.service';
|
|||
import { CipherService } from 'jslib/abstractions/cipher.service';
|
||||
import { FolderService } from 'jslib/abstractions/folder.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { StateService } from 'jslib/abstractions/state.service';
|
||||
|
@ -40,7 +41,7 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit {
|
|||
analytics: Angulartics2, toasterService: ToasterService,
|
||||
auditService: AuditService, stateService: StateService,
|
||||
protected tokenService: TokenService, protected totpService: TotpService,
|
||||
protected passwordGenerationService: PasswordGenerationService) {
|
||||
protected passwordGenerationService: PasswordGenerationService, protected messagingService: MessagingService) {
|
||||
super(cipherService, folderService, i18nService, platformUtilsService, analytics,
|
||||
toasterService, auditService, stateService);
|
||||
}
|
||||
|
@ -94,6 +95,18 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit {
|
|||
return confirmed;
|
||||
}
|
||||
|
||||
async premiumRequired() {
|
||||
const premium = await this.tokenService.getPremium();
|
||||
if (!premium) {
|
||||
this.messagingService.send('premiumRequired');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
async upgradeOrganization() {
|
||||
this.messagingService.send('upgradeOrganization', { organizationId: this.cipher.organizationId });
|
||||
}
|
||||
|
||||
protected cleanUp() {
|
||||
if (this.totpInterval) {
|
||||
window.clearInterval(this.totpInterval);
|
||||
|
|
|
@ -49,6 +49,17 @@
|
|||
</app-vault-ciphers>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<div class="card border-warning mb-4" *ngIf="showUpdateKey">
|
||||
<div class="card-header bg-warning text-white">
|
||||
<i class="fa fa-warning fa-fw"></i> {{'updateKeyTitle' | i18n}}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>{{'updateEncryptionKeyShortDesc' | i18n}}</p>
|
||||
<button class="btn btn-block btn-outline-secondary" type="button" (click)="updateKey()">
|
||||
{{'updateEncryptionKey' | i18n}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<app-verify-email *ngIf="showVerifyEmail" class="d-block mb-4"></app-verify-email>
|
||||
<div class="card border-warning mb-4" *ngIf="showBrowserOutdated">
|
||||
<div class="card-header bg-warning text-white">
|
||||
|
@ -61,17 +72,6 @@
|
|||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card border-warning mb-4" *ngIf="showUpdateKey">
|
||||
<div class="card-header bg-warning text-white">
|
||||
<i class="fa fa-warning fa-fw"></i> {{'updateKeyTitle' | i18n}}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>{{'updateEncryptionKeyShortDesc' | i18n}}</p>
|
||||
<button class="btn btn-block btn-outline-secondary" type="button" (click)="updateKey()">
|
||||
{{'updateEncryptionKey' | i18n}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
{{'organizations' | i18n}}
|
||||
|
|
|
@ -32,8 +32,10 @@ import { ShareComponent } from './share.component';
|
|||
|
||||
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { SyncService } from 'jslib/abstractions/sync.service';
|
||||
import { TokenService } from 'jslib/abstractions/token.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-vault',
|
||||
|
@ -66,7 +68,8 @@ export class VaultComponent implements OnInit {
|
|||
constructor(private syncService: SyncService, private route: ActivatedRoute,
|
||||
private router: Router, private location: Location,
|
||||
private i18nService: I18nService, private componentFactoryResolver: ComponentFactoryResolver,
|
||||
private tokenService: TokenService, private cryptoService: CryptoService) { }
|
||||
private tokenService: TokenService, private cryptoService: CryptoService,
|
||||
private messagingService: MessagingService, private userService: UserService) { }
|
||||
|
||||
async ngOnInit() {
|
||||
this.showVerifyEmail = !(await this.tokenService.getEmailVerified());
|
||||
|
@ -157,7 +160,19 @@ export class VaultComponent implements OnInit {
|
|||
this.ciphersComponent.searchText = searchText;
|
||||
}
|
||||
|
||||
editCipherAttachments(cipher: CipherView) {
|
||||
async editCipherAttachments(cipher: CipherView) {
|
||||
const premium = await this.tokenService.getPremium();
|
||||
if (cipher.organizationId == null && !premium) {
|
||||
this.messagingService.send('premiumRequired');
|
||||
return;
|
||||
} else if (cipher.organizationId != null) {
|
||||
const org = await this.userService.getOrganization(cipher.organizationId);
|
||||
if (org != null && (org.maxStorageGb == null || org.maxStorageGb === 0)) {
|
||||
this.messagingService.send('upgradeOrganization', { organizationId: cipher.organizationId });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.modal != null) {
|
||||
this.modal.close();
|
||||
}
|
||||
|
|
|
@ -1026,6 +1026,12 @@
|
|||
"premiumMembership": {
|
||||
"message": "Premium Membership"
|
||||
},
|
||||
"premiumRequired": {
|
||||
"message": "Premium Required"
|
||||
},
|
||||
"premiumRequiredDesc": {
|
||||
"message": "A premium membership is required to use this feature."
|
||||
},
|
||||
"manage": {
|
||||
"message": "Manage"
|
||||
},
|
||||
|
@ -2301,5 +2307,14 @@
|
|||
},
|
||||
"loading": {
|
||||
"message": "Loading"
|
||||
},
|
||||
"upgrade": {
|
||||
"message": "Upgrade"
|
||||
},
|
||||
"upgradeOrganization": {
|
||||
"message": "Upgrade Organization"
|
||||
},
|
||||
"upgradeOrganizationDesc": {
|
||||
"message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features."
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue