mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-27 12:36:14 +01:00
org settings and billing
This commit is contained in:
parent
7591843220
commit
80e4d2329a
8
src/app/filters/jsonDateFilter.js
Normal file
8
src/app/filters/jsonDateFilter.js
Normal file
@ -0,0 +1,8 @@
|
||||
angular
|
||||
.module('bit.filters')
|
||||
|
||||
.filter('jsonDate', function () {
|
||||
return function (input) {
|
||||
return input.split('T').join(' ');
|
||||
};
|
||||
});
|
@ -1,6 +1,72 @@
|
||||
angular
|
||||
.module('bit.organization')
|
||||
|
||||
.controller('organizationBillingController', function ($scope) {
|
||||
.controller('organizationBillingController', function ($scope, apiService, $state) {
|
||||
$scope.charges = [];
|
||||
$scope.paymentSource = null;
|
||||
$scope.plan = null;
|
||||
$scope.subscription = null;
|
||||
$scope.loading = true;
|
||||
|
||||
$scope.$on('$viewContentLoaded', function () {
|
||||
apiService.organizations.getBilling({ id: $state.params.orgId }, function (org) {
|
||||
$scope.loading = false;
|
||||
|
||||
$scope.plan = {
|
||||
name: org.Plan,
|
||||
type: org.PlanType,
|
||||
maxUsers: org.MaxUsers
|
||||
};
|
||||
|
||||
$scope.subscription = {
|
||||
trialEndDate: org.Subscription.TrialEndDate,
|
||||
nextBillDate: org.Subscription.NextBillDate,
|
||||
cancelNext: org.Subscription.CancelAtNextBillDate,
|
||||
status: org.Subscription.Status
|
||||
};
|
||||
|
||||
if (org.Subscription.Items) {
|
||||
$scope.subscription.items = [];
|
||||
for (var i = 0; i < org.Subscription.Items.length; i++) {
|
||||
$scope.subscription.items.push({
|
||||
amount: org.Subscription.Items[i].Amount,
|
||||
name: org.Subscription.Items[i].Name,
|
||||
interval: org.Subscription.Items[i].Interval,
|
||||
qty: org.Subscription.Items[i].Quantity
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (org.PaymentSource) {
|
||||
$scope.paymentSource = {
|
||||
type: org.PaymentSource.Type,
|
||||
description: org.PaymentSource.Description,
|
||||
cardBrand: org.PaymentSource.CardBrand
|
||||
};
|
||||
}
|
||||
|
||||
var charges = [];
|
||||
for (var i = 0; i < org.Charges.length; i++) {
|
||||
charges.push({
|
||||
date: org.Charges[i].CreatedDate,
|
||||
paymentSource: org.Charges[i].PaymentSource ? org.Charges[i].PaymentSource.Description : '-',
|
||||
amount: org.Charges[i].Amount,
|
||||
status: org.Charges[i].Status,
|
||||
failureMessage: org.Charges[i].FailureMessage,
|
||||
refunded: org.Charges[i].Refunded,
|
||||
partiallyRefunded: org.Charges[i].PartiallyRefunded,
|
||||
refundedAmount: org.Charges[i].RefundedAmount
|
||||
});
|
||||
}
|
||||
$scope.charges = charges;
|
||||
});
|
||||
});
|
||||
|
||||
$scope.changePayment = function () {
|
||||
|
||||
};
|
||||
|
||||
$scope.cancel = function () {
|
||||
|
||||
};
|
||||
});
|
||||
|
@ -1,6 +1,23 @@
|
||||
angular
|
||||
.module('bit.organization')
|
||||
|
||||
.controller('organizationSettingsController', function ($scope) {
|
||||
|
||||
.controller('organizationSettingsController', function ($scope, $state, apiService, toastr, authService) {
|
||||
$scope.model = {};
|
||||
$scope.$on('$viewContentLoaded', function () {
|
||||
apiService.organizations.get({ id: $state.params.orgId }, function (org) {
|
||||
$scope.model = {
|
||||
name: org.Name,
|
||||
billingEmail: org.BillingEmail,
|
||||
businessName: org.BusinessName
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
$scope.generalSave = function () {
|
||||
$scope.generalPromise = apiService.organizations.put({ id: $state.params.orgId }, $scope.model, function (org) {
|
||||
authService.updateProfileOrganization(org).then(function (updatedOrg) {
|
||||
toastr.success('Organization has been updated.', 'Success!');
|
||||
});
|
||||
}).$promise;
|
||||
};
|
||||
});
|
||||
|
@ -7,10 +7,110 @@
|
||||
<section class="content">
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title"><i class="fa fa-server"></i> My Org</h3>
|
||||
<h3 class="box-title">Plan</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
Some data
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<dl>
|
||||
<dt>Name</dt>
|
||||
<dd>{{plan.name}}</dd>
|
||||
<dt>Maximum Users</dt>
|
||||
<dd>{{plan.maxUsers}}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<dl>
|
||||
<dt>Status</dt>
|
||||
<dd style="text-transform: capitalize;">{{subscription.status}}</dd>
|
||||
<dt>Next Bill Date</dt>
|
||||
<dd>{{subscription.nextBillDate | jsonDate}}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<strong>Details</strong>
|
||||
<div ng-show="loading">
|
||||
Loading...
|
||||
</div>
|
||||
<div class="table-responsive" style="margin: 0;" ng-show="!loading">
|
||||
<table class="table" style="margin: 0;">
|
||||
<tbody>
|
||||
<tr ng-repeat="item in subscription.items">
|
||||
<td>
|
||||
{{item.name}} {{item.qty > 1 ? '×' + item.qty : ''}}
|
||||
@ {{item.amount | currency:'$'}} /{{item.interval}}
|
||||
</td>
|
||||
<td class="text-right">{{(item.qty * item.amount) | currency:'$'}} /{{item.interval}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
<button type="button" class="btn btn-default btn-flat" ng-click="changePlan()">
|
||||
Change Plan
|
||||
</button>
|
||||
<button type="button" class="btn btn-default btn-flat" ng-click="cancel()">
|
||||
Cancel Plan
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Payment Method</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div ng-show="loading">
|
||||
Loading...
|
||||
</div>
|
||||
<div ng-show="!loading && !paymentMethod">
|
||||
<i class="fa fa-credit-card"></i> No payment method on file.
|
||||
</div>
|
||||
<div ng-show="!loading && paymentMethod">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
<button type="button" class="btn btn-default btn-flat" ng-click="changePayment()">
|
||||
{{ paymentMethod ? 'Change Payment Method' : 'Add Payment Method' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Charges</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div ng-show="loading">
|
||||
Loading...
|
||||
</div>
|
||||
<div ng-show="!loading && !charges.length">
|
||||
No charges.
|
||||
</div>
|
||||
<div class="table-responsive" ng-show="charges.length">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr ng-repeat="charge in charges">
|
||||
<td style="width: 200px">
|
||||
{{charge.date | jsonDate}}
|
||||
</td>
|
||||
<td>
|
||||
{{charge.paymentSource}}
|
||||
</td>
|
||||
<td style="width: 150px; text-transform: capitalize;">
|
||||
{{charge.status}}
|
||||
</td>
|
||||
<td class="text-right" style="width: 150px;">
|
||||
{{charge.amount | currency:'$'}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
@ -5,12 +5,48 @@
|
||||
</h1>
|
||||
</section>
|
||||
<section class="content">
|
||||
<div class="box">
|
||||
<div class="box box-default">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title"><i class="fa fa-server"></i> My Org</h3>
|
||||
<h3 class="box-title">General</h3>
|
||||
</div>
|
||||
<form role="form" name="generalForm" ng-submit="generalForm.$valid && generalSave()" api-form="generalPromise">
|
||||
<div class="box-body">
|
||||
Some data
|
||||
<div class="row">
|
||||
<div class="col-sm-9">
|
||||
<div class="callout callout-danger validation-errors" ng-show="generalForm.$errors">
|
||||
<h4>Errors have occured</h4>
|
||||
<ul>
|
||||
<li ng-repeat="e in generalForm.$errors">{{e}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="form-group" show-errors>
|
||||
<label for="name">Organization Name</label>
|
||||
<input type="text" id="name" name="Name" ng-model="model.name" class="form-control"
|
||||
required api-field />
|
||||
</div>
|
||||
<div class="form-group" show-errors>
|
||||
<label for="name">Business Name</label>
|
||||
<input type="text" id="businessName" name="BusinessName" ng-model="model.businessName"
|
||||
class="form-control" api-field />
|
||||
</div>
|
||||
<div class="form-group" show-errors>
|
||||
<label for="name">Billing Email</label>
|
||||
<input type="email" id="billingEmail" name="BillingEmail" ng-model="model.billingEmail"
|
||||
class="form-control" required api-field />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3 settings-photo">
|
||||
<letter-avatar data="{{model.name}}" round="false"
|
||||
avclass="img-responsive img-rounded" avwidth="200" avheight="200"
|
||||
fontsize="90"></letter-avatar>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
<button type="submit" class="btn btn-primary btn-flat" ng-disabled="generalForm.$loading">
|
||||
<i class="fa fa-refresh fa-spin loading-icon" ng-show="generalForm.$loading"></i>Save
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
|
@ -35,6 +35,7 @@
|
||||
|
||||
_service.organizations = $resource(_apiUri + '/organizations/:id', {}, {
|
||||
get: { method: 'GET', params: { id: '@id' } },
|
||||
getBilling: { url: _apiUri + '/organizations/:id/billing', method: 'GET', params: { id: '@id' } },
|
||||
list: { method: 'GET', params: {} },
|
||||
post: { method: 'POST', params: {} },
|
||||
put: { method: 'POST', params: { id: '@id' } },
|
||||
|
@ -140,6 +140,17 @@ angular
|
||||
});
|
||||
};
|
||||
|
||||
_service.updateProfileOrganization = function (org) {
|
||||
return _service.getUserProfile().then(function (profile) {
|
||||
if (profile) {
|
||||
if (profile.organizations && org.Id in profile.organizations) {
|
||||
profile.organizations[org.Id].name = org.Name;
|
||||
_userProfile = profile;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
_service.isAuthenticated = function () {
|
||||
return tokenService.getToken() !== null;
|
||||
};
|
||||
|
@ -93,6 +93,7 @@
|
||||
<script src="app/filters/filtersModule.js"></script>
|
||||
<script src="app/filters/enumNameFilter.js"></script>
|
||||
<script src="app/filters/enumLabelClassFilter.js"></script>
|
||||
<script src="app/filters/jsonDateFilter.js"></script>
|
||||
|
||||
<script src="app/services/servicesModule.js"></script>
|
||||
<script src="app/services/tokenService.js"></script>
|
||||
|
Loading…
Reference in New Issue
Block a user