1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-12-28 17:27:50 +01:00

premium membership component

This commit is contained in:
Kyle Spearrin 2018-02-16 15:03:29 -05:00
parent 54d2742604
commit 830a437f1e
8 changed files with 220 additions and 4 deletions

View File

@ -0,0 +1,62 @@
<div class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<div class="box">
<div class="box-header">
{{'premiumMembership' | i18n}}
</div>
<div class="box-content box-content-padded">
<div *ngIf="!isPremium">
<p class="text-center lead">{{'premiumNotCurrentMember' | i18n}}</p>
<p>{{'premiumSignUpAndGet' | i18n}}</p>
<ul class="fa-ul">
<li>
<i class="fa-li fa fa-check text-success"></i>
{{'premiumSignUpStorage' | i18n}}
</li>
<li>
<i class="fa-li fa fa-check text-success"></i>
{{'premiumSignUpTwoStep' | i18n}}
</li>
<li>
<i class="fa-li fa fa-check text-success"></i>
{{'premiumSignUpTotp' | i18n}}
</li>
<li>
<i class="fa-li fa fa-check text-success"></i>
{{'premiumSignUpSupport' | i18n}}
</li>
<li>
<i class="fa-li fa fa-check text-success"></i>
{{'premiumSignUpFuture' | i18n}}
</li>
</ul>
<p class="text-center lead no-margin">{{'premiumPrice' | i18n : price}}</p>
</div>
<div *ngIf="isPremium">
<p class="text-center lead">{{'premiumCurrentMember' | i18n}}</p>
<p class="text-center">{{'premiumCurrentMemberThanks' | i18n}}</p>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="primary" appBlurClick (click)="manage()" *ngIf="isPremium">
<b>{{'premiumManage' | i18n}}</b>
</button>
<button type="button" class="primary" appBlurClick (click)="purchase()" *ngIf="!isPremium">
<b>{{'premiumPurchase' | i18n}}</b>
</button>
<button type="button" data-dismiss="modal">{{'close' | i18n}}</button>
<div class="right" *ngIf="!isPremium">
<button #refreshBtn type="button" appBlurClick (click)="refresh()" [disabled]="refreshBtn.loading"
title="{{'premiumRefresh' | i18n}}" [appApiAction]="refreshPromise">
<i class="fa fa-refresh fa-lg fa-fw" [hidden]="refreshBtn.loading"></i>
<i class="fa fa-spinner fa-spin fa-lg fa-fw" [hidden]="!refreshBtn.loading"></i>
</button>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,59 @@
import * as template from './premium.component.html';
import {
Component,
OnInit,
} from '@angular/core';
import { ToasterService } from 'angular2-toaster';
import { Angulartics2 } from 'angulartics2';
import { ApiService } from 'jslib/abstractions/api.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { TokenService } from 'jslib/abstractions/token.service';
@Component({
selector: 'app-premium',
template: template,
})
export class PremiumComponent implements OnInit {
isPremium: boolean = false;
price: string = '$10';
refreshPromise: Promise<any>;
constructor(private analytics: Angulartics2, private toasterService: ToasterService,
private i18nService: I18nService, private platformUtilsService: PlatformUtilsService,
private tokenService: TokenService, private apiService: ApiService) { }
async ngOnInit() {
this.isPremium = !this.tokenService.getPremium();
}
async refresh() {
try {
this.refreshPromise = this.apiService.refreshIdentityToken();
await this.refreshPromise;
this.toasterService.popAsync('success', null, this.i18nService.t('refreshComplete'));
this.isPremium = this.tokenService.getPremium();
} catch { }
}
async purchase() {
const confirmed = await this.platformUtilsService.showDialog(this.i18nService.t('premiumPurchaseAlert'),
this.i18nService.t('premiumPurchase'), this.i18nService.t('yes'), this.i18nService.t('cancel'));
if (confirmed) {
this.analytics.eventTrack.next({ action: 'Clicked Purchase Premium' });
this.platformUtilsService.launchUri('https://vault.bitwarden.com/#/?premium=purchase');
}
}
async manage() {
const confirmed = await this.platformUtilsService.showDialog(this.i18nService.t('premiumManageAlert'),
this.i18nService.t('premiumManage'), this.i18nService.t('yes'), this.i18nService.t('cancel'));
if (confirmed) {
this.analytics.eventTrack.next({ action: 'Clicked Manage Membership' });
this.platformUtilsService.launchUri('https://vault.bitwarden.com/#/?premium=manage');
}
}
}

View File

@ -17,6 +17,7 @@ import { Router } from '@angular/router';
import { ModalComponent } from './modal.component'; import { ModalComponent } from './modal.component';
import { PremiumComponent } from './accounts/premium.component';
import { SettingsComponent } from './accounts/settings.component'; import { SettingsComponent } from './accounts/settings.component';
import { ToasterService } from 'angular2-toaster'; import { ToasterService } from 'angular2-toaster';
@ -49,10 +50,12 @@ const BroadcasterSubscriptionId = 'AppComponent';
template: ` template: `
<toaster-container [toasterconfig]="toasterConfig"></toaster-container> <toaster-container [toasterconfig]="toasterConfig"></toaster-container>
<ng-template #settings></ng-template> <ng-template #settings></ng-template>
<ng-template #premium></ng-template>
<router-outlet></router-outlet>`, <router-outlet></router-outlet>`,
}) })
export class AppComponent implements OnInit { export class AppComponent implements OnInit {
@ViewChild('settings', { read: ViewContainerRef }) settingsRef: ViewContainerRef; @ViewChild('settings', { read: ViewContainerRef }) settingsRef: ViewContainerRef;
@ViewChild('premium', { read: ViewContainerRef }) premiumRef: ViewContainerRef;
toasterConfig: ToasterConfig = new ToasterConfig({ toasterConfig: ToasterConfig = new ToasterConfig({
showCloseButton: true, showCloseButton: true,
@ -113,6 +116,9 @@ export class AppComponent implements OnInit {
case 'openSettings': case 'openSettings':
this.openSettings(); this.openSettings();
break; break;
case 'openPremium':
this.openPremium();
break;
default: default:
} }
}); });
@ -177,4 +183,18 @@ export class AppComponent implements OnInit {
this.modal = null; this.modal = null;
}); });
} }
private openPremium() {
if (this.modal != null) {
this.modal.close();
}
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent);
this.modal = this.premiumRef.createComponent(factory).instance;
const childComponent = this.modal.show<PremiumComponent>(PremiumComponent, this.premiumRef);
this.modal.onClosed.subscribe(() => {
this.modal = null;
});
}
} }

View File

@ -20,6 +20,7 @@ import { EnvironmentComponent } from './accounts/environment.component';
import { HintComponent } from './accounts/hint.component'; import { HintComponent } from './accounts/hint.component';
import { LockComponent } from './accounts/lock.component'; import { LockComponent } from './accounts/lock.component';
import { LoginComponent } from './accounts/login.component'; import { LoginComponent } from './accounts/login.component';
import { PremiumComponent } from './accounts/premium.component';
import { RegisterComponent } from './accounts/register.component'; import { RegisterComponent } from './accounts/register.component';
import { SettingsComponent } from './accounts/settings.component'; import { SettingsComponent } from './accounts/settings.component';
import { TwoFactorOptionsComponent } from './accounts/two-factor-options.component'; import { TwoFactorOptionsComponent } from './accounts/two-factor-options.component';
@ -80,6 +81,7 @@ import { ViewComponent } from './vault/view.component';
LoginComponent, LoginComponent,
ModalComponent, ModalComponent,
PasswordGeneratorComponent, PasswordGeneratorComponent,
PremiumComponent,
RegisterComponent, RegisterComponent,
SearchCiphersPipe, SearchCiphersPipe,
SettingsComponent, SettingsComponent,
@ -96,6 +98,7 @@ import { ViewComponent } from './vault/view.component';
FolderAddEditComponent, FolderAddEditComponent,
ModalComponent, ModalComponent,
PasswordGeneratorComponent, PasswordGeneratorComponent,
PremiumComponent,
SettingsComponent, SettingsComponent,
TwoFactorOptionsComponent, TwoFactorOptionsComponent,
], ],

View File

@ -650,9 +650,6 @@
"syncVault": { "syncVault": {
"message": "Sync Vault" "message": "Sync Vault"
}, },
"premiumMembership": {
"message": "Premium Membership"
},
"changeMasterPass": { "changeMasterPass": {
"message": "Change Master Password" "message": "Change Master Password"
}, },
@ -814,5 +811,62 @@
"copySecurityCode": { "copySecurityCode": {
"message": "Copy Security Code", "message": "Copy Security Code",
"description": "Copy credit card security code (CVV)" "description": "Copy credit card security code (CVV)"
},
"premiumMembership": {
"message": "Premium Membership"
},
"premiumManage": {
"message": "Manage Membership"
},
"premiumManageAlert": {
"message": "You can manage your membership on the bitwarden.com web vault. Do you want to visit the website now?"
},
"premiumRefresh": {
"message": "Refresh Membership"
},
"premiumNotCurrentMember": {
"message": "You are not currently a premium member."
},
"premiumSignUpAndGet": {
"message": "Sign up for a premium membership and get:"
},
"premiumSignUpStorage": {
"message": "1 GB of encrypted file storage."
},
"premiumSignUpTwoStep": {
"message": "Additional two-step login options such as YubiKey, FIDO U2F, and Duo."
},
"premiumSignUpTotp": {
"message": "TOTP verification code (2FA) generator for logins in your vault."
},
"premiumSignUpSupport": {
"message": "Priority customer support."
},
"premiumSignUpFuture": {
"message": "All future premium features. More coming soon!"
},
"premiumPurchase": {
"message": "Purchase Premium"
},
"premiumPurchaseAlert": {
"message": "You can purchase premium membership on the bitwarden.com web vault. Do you want to visit the website now?"
},
"premiumCurrentMember": {
"message": "You are a premium member!"
},
"premiumCurrentMemberThanks": {
"message": "Thank you for supporting bitwarden."
},
"premiumPrice": {
"message": "All for just $PRICE$ /year!",
"placeholders": {
"price": {
"content": "$1",
"example": "$10"
}
}
},
"refreshComplete": {
"message": "Refresh complete"
} }
} }

View File

@ -203,7 +203,7 @@ export class MenuMain {
submenu: [ submenu: [
{ {
label: this.main.i18nService.t('premiumMembership'), label: this.main.i18nService.t('premiumMembership'),
click: () => this.main.messagingService.send('premiumMembership'), click: () => this.main.messagingService.send('openPremium'),
id: 'premiumMembership', id: 'premiumMembership',
}, },
{ {

View File

@ -24,6 +24,10 @@ p {
margin-bottom: 10px; margin-bottom: 10px;
} }
ul, ol {
margin-bottom: 10px;
}
img { img {
border: none; border: none;
} }

View File

@ -8,6 +8,10 @@ small {
color: $brand-primary !important; color: $brand-primary !important;
} }
.text-success {
color: $brand-success !important;
}
.text-muted { .text-muted {
color: $text-muted !important; color: $text-muted !important;
} }
@ -20,6 +24,16 @@ small {
text-align: center; text-align: center;
} }
.no-margin {
margin: 0 !important;
}
p.lead {
font-size: $font-size-large;
margin-bottom: 20px;
font-weight: normal;
}
[hidden] { [hidden] {
display: none !important; display: none !important;
} }