1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-11-27 12:36:14 +01:00

premium membership page

This commit is contained in:
Kyle Spearrin 2017-07-13 22:33:34 -04:00
parent 1c693a45b3
commit 3a8f149008
9 changed files with 255 additions and 35 deletions

View File

@ -762,5 +762,73 @@
"updateKey": { "updateKey": {
"message": "You cannot use this feature until you update your encryption key.", "message": "You cannot use this feature until you update your encryption key.",
"description": "You cannot use this feature until you update your encryption key." "description": "You cannot use this feature until you update your encryption key."
},
"premiumMembership": {
"message": "Premium Membership",
"description": "Premium Membership"
},
"premiumManage": {
"message": "Manage Membership",
"description": "Manage Membership"
},
"premiumManageAlert": {
"message": "You can manage your membership on the bitwarden.com web vault. Do you want to visit the website now?",
"description": "You can manage your membership on the bitwarden.com web vault. Do you want to visit the website now?"
},
"premiumRefresh": {
"message": "Refresh Membership",
"description": "Refresh Membership"
},
"premiumNotCurrentMember": {
"message": "You are not currently a premium member.",
"description": "You are not currently a premium member."
},
"premiumSignUpAndGet": {
"message": "Sign up for a premium membership and get:",
"description": "Sign up for a premium membership and get:"
},
"ppremiumSignUpStorage": {
"message": "1 GB of encrypted file storage.",
"description": "1 GB of encrypted file storage."
},
"ppremiumSignUpTwoStep": {
"message": "Additional two-step login options such as YubiKey, FIDO U2F, and Duo.",
"description": "Additional two-step login options such as YubiKey, FIDO U2F, and Duo."
},
"ppremiumSignUpTotp": {
"message": "TOTP verification code (2FA) generator for logins in your vault.",
"description": "TOTP verification code (2FA) generator for logins in your vault."
},
"ppremiumSignUpSupport": {
"message": "Priority customer support.",
"description": "Priority customer support."
},
"ppremiumSignUpFuture": {
"message": "All future premium features. More coming soon!",
"description": "All future premium features. More coming soon!"
},
"premiumPurchase": {
"message": "Purchase Premium",
"description": "Purchase Premium"
},
"premiumPurchaseAlert": {
"message": "You can purchase premium membership on the bitwarden.com web vault. Do you want to visit the website now?",
"description": "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!",
"description": "You are a premium member!"
},
"premiumCurrentMemberThanks": {
"message": "Thank you for supporting bitwarden.",
"description": "Thank you for supporting bitwarden."
},
"premiumPrice": {
"message": "All for just %price% /year!",
"description": "All for just %price% /year!"
},
"refreshComplete": {
"message": "Refresh complete",
"description": "Refresh complete"
} }
} }

View File

@ -198,6 +198,13 @@
data: { authorize: true }, data: { authorize: true },
params: { animation: null } params: { animation: null }
}) })
.state('premium', {
url: '/premium',
templateUrl: 'app/settings/views/settingsPremium.html',
controller: 'settingsPremiumController',
data: { authorize: true },
params: { animation: null }
})
.state('folders', { .state('folders', {
url: '/folders', url: '/folders',

View File

@ -2,7 +2,7 @@
<div class="home-page"> <div class="home-page">
<img src="../../../../images/logo@3x.png" alt="bitwarden" /> <img src="../../../../images/logo@3x.png" alt="bitwarden" />
<p>{{i18n.loginOrCreateNewAccount}}</p> <p>{{i18n.loginOrCreateNewAccount}}</p>
<div class="buttons"> <div class="bottom-buttons">
<a class="btn btn-lg btn-primary btn-block" ui-sref="register({animation: 'in-slide-up'})" <a class="btn btn-lg btn-primary btn-block" ui-sref="register({animation: 'in-slide-up'})"
analytics-on="click" analytics-event="Clicked Create Account"> analytics-on="click" analytics-event="Clicked Create Account">
<b>{{i18n.createAccount}}</b> <b>{{i18n.createAccount}}</b>

View File

@ -0,0 +1,50 @@
angular
.module('bit.settings')
.controller('settingsPremiumController', function ($scope, i18nService, tokenService, apiService, toastr, SweetAlert,
$analytics, $timeout) {
$scope.i18n = i18nService;
$scope.isPremium = tokenService.getPremium();
$scope.price = '$10';
$scope.refresh = function () {
apiService.refreshIdentityToken(function () {
toastr.success(i18nService.refreshComplete);
$timeout(function () {
$scope.isPremium = tokenService.getPremium();
});
}, function (err) {
toastr.error(i18nService.errorsOccurred);
});
};
$scope.purchase = function () {
SweetAlert.swal({
title: i18nService.premiumPurchase,
text: i18nService.premiumPurchaseAlert,
showCancelButton: true,
confirmButtonText: i18nService.yes,
cancelButtonText: i18nService.cancel
}, function (confirmed) {
$analytics.eventTrack('Clicked Purchase Premium');
if (confirmed) {
chrome.tabs.create({ url: 'https://vault.bitwarden.com/#/?premium=purchase' });
}
});
};
$scope.manage = function () {
SweetAlert.swal({
title: i18nService.premiumManage,
text: i18nService.premiumManageAlert,
showCancelButton: true,
confirmButtonText: i18nService.yes,
cancelButtonText: i18nService.cancel
}, function (confirmed) {
$analytics.eventTrack('Clicked Manage Membership');
if (confirmed) {
chrome.tabs.create({ url: 'https://vault.bitwarden.com/#/?premium=manage' });
}
});
};
});

View File

@ -38,6 +38,10 @@
{{i18n.account}} {{i18n.account}}
</div> </div>
<div class="list-section-items"> <div class="list-section-items">
<a class="list-section-item text-primary" ui-sref="premium({animation: 'in-slide-left'})">
<i class="fa fa-star fa-fw"></i> <b>{{i18n.premiumMembership}}</b>
<i class="fa fa-chevron-right fa-lg"></i>
</a>
<a class="list-section-item" href="" ng-click="changePassword()"> <a class="list-section-item" href="" ng-click="changePassword()">
{{i18n.changeMasterPassword}} {{i18n.changeMasterPassword}}
<i class="fa fa-chevron-right fa-lg"></i> <i class="fa fa-chevron-right fa-lg"></i>

View File

@ -0,0 +1,54 @@
<div class="header">
<div class="left">
<a ui-sref="tabs.settings({animation: 'out-slide-right'})"><i class="fa fa-chevron-left"></i> {{i18n.settings}}</a>
</div>
<div class="title">{{i18n.premiumMembership}}</div>
</div>
<div class="content">
<div class="premium-page">
<div ng-if="!isPremium">
<p class="text-center lead">{{i18n.premiumNotCurrentMember}}</p>
<p>{{i18n.premiumSignUpAndGet}}</p>
<ul class="fa-ul">
<li>
<i class="fa-li fa fa-check text-success"></i>
{{i18n.ppremiumSignUpStorage}}
</li>
<li>
<i class="fa-li fa fa-check text-success"></i>
{{i18n.ppremiumSignUpTwoStep}}
</li>
<li>
<i class="fa-li fa fa-check text-success"></i>
T{{i18n.ppremiumSignUpTotp}}
</li>
<li>
<i class="fa-li fa fa-check text-success"></i>
{{i18n.ppremiumSignUpSupport}}
</li>
<li>
<i class="fa-li fa fa-check text-success"></i>
{{i18n.ppremiumSignUpFuture}}
</li>
</ul>
<p class="text-center lead">{{i18n.premiumPrice.replace('%price%', price)}}</p>
<div class="bottom-buttons">
<a class="btn btn-lg btn-primary btn-block" href="#" stop-click ng-click="purchase()">
<b>{{i18n.premiumPurchase}}</b>
</a>
<a class="btn btn-lg btn-link btn-block" href="#" stop-click ng-click="refresh()">
{{i18n.premiumRefresh}}
</a>
</div>
</div>
<div ng-if="isPremium">
<p class="text-center lead">{{i18n.premiumCurrentMember}}</p>
<p class="text-center">{{i18n.premiumCurrentMemberThanks}}</p>
<div class="bottom-buttons">
<a class="btn btn-lg btn-primary btn-block" href="#" stop-click ng-click="manage()">
<b>{{i18n.premiumManage}}</b>
</a>
</div>
</div>
</div>
</div>

View File

@ -84,6 +84,7 @@
<script src="app/settings/settingsFoldersController.js"></script> <script src="app/settings/settingsFoldersController.js"></script>
<script src="app/settings/settingsAddFolderController.js"></script> <script src="app/settings/settingsAddFolderController.js"></script>
<script src="app/settings/settingsEditFolderController.js"></script> <script src="app/settings/settingsEditFolderController.js"></script>
<script src="app/settings/settingsPremiumController.js"></script>
<script src="app/tools/toolsModule.js"></script> <script src="app/tools/toolsModule.js"></script>
<script src="app/tools/toolsController.js"></script> <script src="app/tools/toolsController.js"></script>

View File

@ -37,22 +37,6 @@
p { p {
font-size: 18px; font-size: 18px;
} }
.buttons {
position: absolute;
bottom: 0;
width: 100%;
left: 0;
padding: 20px;
.btn {
font-size: @font-size-base;
}
.btn-link {
font-weight: 600;
}
}
} }
.splash-page { .splash-page {
@ -75,3 +59,35 @@
margin-right: auto; margin-right: auto;
} }
} }
.bottom-buttons {
position: absolute;
bottom: 0;
width: 100%;
left: 0;
padding: 20px;
.btn {
font-size: @font-size-base;
}
.btn-link {
font-weight: 600;
}
}
.premium-page {
padding: 60px 20px 20px;
position: relative;
height: 100%;
p.lead {
font-weight: normal;
font-size: 18px;
margin-bottom: 30px;
}
ul {
margin-bottom: 30px;
}
}

View File

@ -56,6 +56,18 @@ function initApiService() {
}); });
}; };
ApiService.prototype.refreshIdentityToken = function (success, error) {
refreshToken(this, function () {
success();
}, function (jqXHR) {
if (jqXHR) {
handleError(error, jqXHR, false, self);
return;
}
error();
});
};
// Two Factor APIs // Two Factor APIs
ApiService.prototype.postTwoFactorEmail = function (request, success, error) { ApiService.prototype.postTwoFactorEmail = function (request, success, error) {
@ -511,23 +523,10 @@ function initApiService() {
}); });
} // handle token refresh } // handle token refresh
else if (self.tokenService.tokenNeedsRefresh()) { else if (self.tokenService.tokenNeedsRefresh()) {
self.tokenService.getRefreshToken(function (refreshToken) { refreshToken(self, function (accessToken) {
if (!refreshToken || refreshToken === '') { resolveTokenQs(accessToken, self, deferred);
deferred.reject(); }, function (err) {
return; deferred.reject(err);
}
postConnectToken(self, {
grant_type: 'refresh_token',
client_id: 'browser',
refresh_token: refreshToken
}, function (token) {
self.tokenService.setTokens(token.accessToken, token.refreshToken, function () {
resolveTokenQs(token.accessToken, self, deferred);
});
}, function (jqXHR) {
deferred.reject(jqXHR);
});
}); });
} }
else { else {
@ -543,6 +542,27 @@ function initApiService() {
return deferred.promise return deferred.promise
} }
function refreshToken(self, success, error) {
self.tokenService.getRefreshToken(function (refreshToken) {
if (!refreshToken || refreshToken === '') {
error();
return;
}
postConnectToken(self, {
grant_type: 'refresh_token',
client_id: 'browser',
refresh_token: refreshToken
}, function (token) {
self.tokenService.setTokens(token.accessToken, token.refreshToken, function () {
success(token.accessToken);
});
}, function (jqXHR) {
error(jqXHR);
});
});
}
function resolveTokenQs(token, self, deferred) { function resolveTokenQs(token, self, deferred) {
var issuer = self.tokenService.getIssuer(); var issuer = self.tokenService.getIssuer();
if (issuer === self.baseUrl) { if (issuer === self.baseUrl) {