adjust payment

This commit is contained in:
Kyle Spearrin 2018-06-30 13:36:39 -04:00
parent 37026e556f
commit d509637623
13 changed files with 128 additions and 13 deletions

2
jslib

@ -1 +1 @@
Subproject commit c0e7e588ed59832a6f579ff63d85bfcdfb400d78
Subproject commit f5287e29a2a135c131d00c4a56a90b18bc4afaab

View File

@ -33,6 +33,7 @@ import { TwoFactorOptionsComponent } from './accounts/two-factor-options.compone
import { TwoFactorComponent } from './accounts/two-factor.component';
import { AccountComponent } from './settings/account.component';
import { AdjustPaymentComponent } from './settings/adjust-payment.component';
import { AdjustStorageComponent } from './settings/adjust-storage.component';
import { ChangeEmailComponent } from './settings/change-email.component';
import { ChangePasswordComponent } from './settings/change-password.component';
@ -107,6 +108,7 @@ import { SearchCiphersPipe } from 'jslib/angular/pipes/search-ciphers.pipe';
declarations: [
AccountComponent,
AddEditComponent,
AdjustPaymentComponent,
AdjustStorageComponent,
ApiActionDirective,
AppComponent,

View File

@ -0,0 +1,22 @@
<app-callout title="{{'contactSupport' | i18n}}" icon="fa-info-circle" *ngIf="!canChange">
<p>{{'contactSupportPaymentMethod' | i18n}}</p>
<a href="https://bitwarden.com/contact/" target="_blank" rel="noopener" class="btn btn-outline-secondary">
{{'contactSupport' | i18n}}
</a>
<button type="button" class="btn btn-outline-secondary" (click)="cancel()">
{{'close' | i18n}}
</button>
</app-callout>
<form #form class="card" (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate *ngIf="canChange">
<div class="card-body">
<h3 class="card-body-header">{{(currentType != null ? 'changePaymentMethod' : 'addPaymentMethod') | i18n}}</h3>
<app-payment [showOptions]="currentType == null"></app-payment>
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading">
<i class="fa fa-spinner fa-spin"></i>
<span>{{'submit' | i18n}}</span>
</button>
<button type="button" class="btn btn-outline-secondary" (click)="cancel()">
{{'cancel' | i18n}}
</button>
</div>
</form>

View File

@ -0,0 +1,64 @@
import {
Component,
EventEmitter,
Input,
Output,
ViewChild,
} 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 { PaymentRequest } from 'jslib/models/request/paymentRequest';
import { PaymentMethodType } from 'jslib/enums/paymentMethodType';
import { PaymentComponent } from './payment.component';
@Component({
selector: 'app-adjust-payment',
templateUrl: 'adjust-payment.component.html',
})
export class AdjustPaymentComponent {
@ViewChild(PaymentComponent) paymentComponent: PaymentComponent;
@Input() currentType?: PaymentMethodType;
@Input() user = true;
@Output() onAdjusted = new EventEmitter();
@Output() onCanceled = new EventEmitter();
paymentMethodType = PaymentMethodType;
formPromise: Promise<any>;
constructor(private apiService: ApiService, private i18nService: I18nService,
private analytics: Angulartics2, private toasterService: ToasterService) { }
async submit() {
try {
const request = new PaymentRequest();
this.formPromise = this.paymentComponent.createPaymentToken().then((token) => {
request.paymentToken = token;
if (this.user) {
return this.apiService.postAccountPayment(request);
}
});
await this.formPromise;
this.analytics.eventTrack.next({
action: this.currentType == null ? 'Added Payment Method' : 'Changed Payment Method',
});
this.toasterService.popAsync('success', null, this.i18nService.t('updatedPaymentMethod'));
this.onAdjusted.emit();
} catch { }
}
cancel() {
this.onCanceled.emit();
}
get canChange() {
return this.currentType == null || this.currentType === PaymentMethodType.Card;
}
}

View File

@ -1,5 +1,6 @@
<form #form class="card" (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate>
<div class="card-body">
<h3 class="card-body-header">{{(add ? 'addStorage' : 'removeStorage') | i18n}}</h3>
<div class="row">
<div class="form-group col-6">
<label for="storageAdjustment">{{(add ? 'gbStorageAdd' : 'gbStorageRemove') | i18n}}</label>

View File

@ -1,4 +1,4 @@
<div class="my-4 text-lg">
<div class="mb-4 text-lg" *ngIf="showOptions">
<div class="form-check form-check-inline mr-4">
<input class="form-check-input" type="radio" name="Method" id="method-card" value="card" [(ngModel)]="method" (change)="changeMethod()">
<label class="form-check-label" for="method-card">
@ -18,7 +18,7 @@
autocomplete="cc-number">
</div>
<div class="form-group col-7 d-flex align-items-end">
<img src="../../images/cards.png" alt="" width="277" height="32">
<img src="../../images/cards.png" alt="" width="323" height="32">
</div>
<div class="form-group col-4">
<label for="exp_month">{{'expirationMonth' | i18n}}</label>

View File

@ -1,5 +1,6 @@
import {
Component,
Input,
OnInit,
} from '@angular/core';
@ -18,6 +19,8 @@ const Keys = {
templateUrl: 'payment.component.html',
})
export class PaymentComponent implements OnInit {
@Input() showOptions = true;
method = 'card';
card: any = {
number: null,

View File

@ -42,7 +42,7 @@
<strong>{{'total' | i18n}}:</strong> {{total | currency:'USD $'}} /{{'year' | i18n}}
<br>
<small class="text-muted">{{'paymentChargedAnnually' | i18n}}</small>
<h2 class="spaced-header">{{'paymentInformation' | i18n}}</h2>
<h2 class="spaced-header mb-4">{{'paymentInformation' | i18n}}</h2>
<app-payment></app-payment>
<button type="submit" class="btn btn-primary btn-submit" appBlurClick [disabled]="form.loading">
<i class="fa fa-spinner fa-spin"></i>

View File

@ -62,7 +62,7 @@
</ng-container>
<ng-container *ngIf="!selfHosted">
<h2 class="spaced-header">{{'storage' | i18n}}</h2>
<p>{{'subscriptionStorage' | i18n : billing.maxStorageGb : billing.storageName}}</p>
<p>{{'subscriptionStorage' | i18n : billing.maxStorageGb : billing.storageName || '0 MB'}}</p>
<div class="progress">
<div class="progress-bar bg-success" role="progressbar" [ngStyle]="{width: storagePercentage + '%' }" [attr.aria-valuenow]="storagePercentage"
aria-valuemin="0" aria-valuemax="100">{{(storagePercentage / 100) | percent}}</div>
@ -77,7 +77,7 @@
{{'removeStorage' | i18n}}
</button>
</ng-container>
<app-adjust-storage [storageGbPrice]="4" [add]="adjustStorageAdd" [user]="true" (onAdjusted)="adjustedStorage($event)" (onCanceled)="canceledAdjustStorage()"
<app-adjust-storage [storageGbPrice]="4" [add]="adjustStorageAdd" [user]="true" (onAdjusted)="closeStorage(true)" (onCanceled)="closeStorage(false)"
*ngIf="showAdjustStorage"></app-adjust-storage>
</div>
</ng-container>
@ -89,9 +89,12 @@
'fa-paypal text-primary': paymentSource.type === paymentMethodType.PayPal}"></i>
{{paymentSource.description}}
</p>
<button type="button" class="btn btn-outline-secondary" (click)="changePayment()">
<button type="button" class="btn btn-outline-secondary" (click)="changePayment()" *ngIf="!showAdjustPayment">
{{(paymentSource ? 'changePaymentMethod' : 'addPaymentMethod') | i18n}}
</button>
<app-adjust-payment [currentType]="paymentSource != null ? paymentSource.type : null" [user]="true" (onAdjusted)="closePayment(true)"
(onCanceled)="closePayment(false)" *ngIf="showAdjustPayment">
</app-adjust-payment>
<h2 class="spaced-header">{{'charges' | i18n}}</h2>
<p *ngIf="!charges || !charges.length">{{'noCharges' | i18n}}</p>
<table class="table mb-2" *ngIf="charges && charges.length">

View File

@ -27,6 +27,7 @@ export class UserBillingComponent implements OnInit {
firstLoaded = false;
adjustStorageAdd = true;
showAdjustStorage = false;
showAdjustPayment = false;
billing: BillingResponse;
paymentMethodType = PaymentMethodType;
@ -109,17 +110,22 @@ export class UserBillingComponent implements OnInit {
this.showAdjustStorage = true;
}
adjustedStorage(gbAmount: number) {
this.showAdjustStorage = false;
this.load();
}
canceledAdjustStorage() {
closeStorage(load: boolean) {
this.showAdjustStorage = false;
if (load) {
this.load();
}
}
changePayment() {
this.showAdjustPayment = true;
}
closePayment(load: boolean) {
this.showAdjustPayment = false;
if (load) {
this.load();
}
}
get subscriptionMarkedForCancel() {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -1404,5 +1404,14 @@
"example": "5"
}
}
},
"contactSupport": {
"message": "Contact Customer Support"
},
"contactSupportPaymentMethod": {
"message": "If you would like to change from this payment method please contact customer support."
},
"updatedPaymentMethod": {
"message": "Updated payment method."
}
}

View File

@ -132,6 +132,11 @@ body {
}
}
.card-body-header {
font-size: $h3-font-size * 1.12;
@extend .mb-4
}
.card ul.fa-ul.card-ul {
margin-left: 1.9em;