mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 08:13:42 +00:00
adjust payment
This commit is contained in:
2
jslib
2
jslib
Submodule jslib updated: c0e7e588ed...f5287e29a2
@@ -33,6 +33,7 @@ import { TwoFactorOptionsComponent } from './accounts/two-factor-options.compone
|
|||||||
import { TwoFactorComponent } from './accounts/two-factor.component';
|
import { TwoFactorComponent } from './accounts/two-factor.component';
|
||||||
|
|
||||||
import { AccountComponent } from './settings/account.component';
|
import { AccountComponent } from './settings/account.component';
|
||||||
|
import { AdjustPaymentComponent } from './settings/adjust-payment.component';
|
||||||
import { AdjustStorageComponent } from './settings/adjust-storage.component';
|
import { AdjustStorageComponent } from './settings/adjust-storage.component';
|
||||||
import { ChangeEmailComponent } from './settings/change-email.component';
|
import { ChangeEmailComponent } from './settings/change-email.component';
|
||||||
import { ChangePasswordComponent } from './settings/change-password.component';
|
import { ChangePasswordComponent } from './settings/change-password.component';
|
||||||
@@ -107,6 +108,7 @@ import { SearchCiphersPipe } from 'jslib/angular/pipes/search-ciphers.pipe';
|
|||||||
declarations: [
|
declarations: [
|
||||||
AccountComponent,
|
AccountComponent,
|
||||||
AddEditComponent,
|
AddEditComponent,
|
||||||
|
AdjustPaymentComponent,
|
||||||
AdjustStorageComponent,
|
AdjustStorageComponent,
|
||||||
ApiActionDirective,
|
ApiActionDirective,
|
||||||
AppComponent,
|
AppComponent,
|
||||||
|
|||||||
22
src/app/settings/adjust-payment.component.html
Normal file
22
src/app/settings/adjust-payment.component.html
Normal 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>
|
||||||
64
src/app/settings/adjust-payment.component.ts
Normal file
64
src/app/settings/adjust-payment.component.ts
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
<form #form class="card" (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate>
|
<form #form class="card" (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
<h3 class="card-body-header">{{(add ? 'addStorage' : 'removeStorage') | i18n}}</h3>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="form-group col-6">
|
<div class="form-group col-6">
|
||||||
<label for="storageAdjustment">{{(add ? 'gbStorageAdd' : 'gbStorageRemove') | i18n}}</label>
|
<label for="storageAdjustment">{{(add ? 'gbStorageAdd' : 'gbStorageRemove') | i18n}}</label>
|
||||||
|
|||||||
@@ -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">
|
<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()">
|
<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">
|
<label class="form-check-label" for="method-card">
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
autocomplete="cc-number">
|
autocomplete="cc-number">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group col-7 d-flex align-items-end">
|
<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>
|
||||||
<div class="form-group col-4">
|
<div class="form-group col-4">
|
||||||
<label for="exp_month">{{'expirationMonth' | i18n}}</label>
|
<label for="exp_month">{{'expirationMonth' | i18n}}</label>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
|
Input,
|
||||||
OnInit,
|
OnInit,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
|
|
||||||
@@ -18,6 +19,8 @@ const Keys = {
|
|||||||
templateUrl: 'payment.component.html',
|
templateUrl: 'payment.component.html',
|
||||||
})
|
})
|
||||||
export class PaymentComponent implements OnInit {
|
export class PaymentComponent implements OnInit {
|
||||||
|
@Input() showOptions = true;
|
||||||
|
|
||||||
method = 'card';
|
method = 'card';
|
||||||
card: any = {
|
card: any = {
|
||||||
number: null,
|
number: null,
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
<strong>{{'total' | i18n}}:</strong> {{total | currency:'USD $'}} /{{'year' | i18n}}
|
<strong>{{'total' | i18n}}:</strong> {{total | currency:'USD $'}} /{{'year' | i18n}}
|
||||||
<br>
|
<br>
|
||||||
<small class="text-muted">{{'paymentChargedAnnually' | i18n}}</small>
|
<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>
|
<app-payment></app-payment>
|
||||||
<button type="submit" class="btn btn-primary btn-submit" appBlurClick [disabled]="form.loading">
|
<button type="submit" class="btn btn-primary btn-submit" appBlurClick [disabled]="form.loading">
|
||||||
<i class="fa fa-spinner fa-spin"></i>
|
<i class="fa fa-spinner fa-spin"></i>
|
||||||
|
|||||||
@@ -62,7 +62,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container *ngIf="!selfHosted">
|
<ng-container *ngIf="!selfHosted">
|
||||||
<h2 class="spaced-header">{{'storage' | i18n}}</h2>
|
<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">
|
||||||
<div class="progress-bar bg-success" role="progressbar" [ngStyle]="{width: storagePercentage + '%' }" [attr.aria-valuenow]="storagePercentage"
|
<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>
|
aria-valuemin="0" aria-valuemax="100">{{(storagePercentage / 100) | percent}}</div>
|
||||||
@@ -77,7 +77,7 @@
|
|||||||
{{'removeStorage' | i18n}}
|
{{'removeStorage' | i18n}}
|
||||||
</button>
|
</button>
|
||||||
</ng-container>
|
</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>
|
*ngIf="showAdjustStorage"></app-adjust-storage>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
@@ -89,9 +89,12 @@
|
|||||||
'fa-paypal text-primary': paymentSource.type === paymentMethodType.PayPal}"></i>
|
'fa-paypal text-primary': paymentSource.type === paymentMethodType.PayPal}"></i>
|
||||||
{{paymentSource.description}}
|
{{paymentSource.description}}
|
||||||
</p>
|
</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}}
|
{{(paymentSource ? 'changePaymentMethod' : 'addPaymentMethod') | i18n}}
|
||||||
</button>
|
</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>
|
<h2 class="spaced-header">{{'charges' | i18n}}</h2>
|
||||||
<p *ngIf="!charges || !charges.length">{{'noCharges' | i18n}}</p>
|
<p *ngIf="!charges || !charges.length">{{'noCharges' | i18n}}</p>
|
||||||
<table class="table mb-2" *ngIf="charges && charges.length">
|
<table class="table mb-2" *ngIf="charges && charges.length">
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ export class UserBillingComponent implements OnInit {
|
|||||||
firstLoaded = false;
|
firstLoaded = false;
|
||||||
adjustStorageAdd = true;
|
adjustStorageAdd = true;
|
||||||
showAdjustStorage = false;
|
showAdjustStorage = false;
|
||||||
|
showAdjustPayment = false;
|
||||||
billing: BillingResponse;
|
billing: BillingResponse;
|
||||||
paymentMethodType = PaymentMethodType;
|
paymentMethodType = PaymentMethodType;
|
||||||
|
|
||||||
@@ -109,17 +110,22 @@ export class UserBillingComponent implements OnInit {
|
|||||||
this.showAdjustStorage = true;
|
this.showAdjustStorage = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
adjustedStorage(gbAmount: number) {
|
closeStorage(load: boolean) {
|
||||||
this.showAdjustStorage = false;
|
|
||||||
this.load();
|
|
||||||
}
|
|
||||||
|
|
||||||
canceledAdjustStorage() {
|
|
||||||
this.showAdjustStorage = false;
|
this.showAdjustStorage = false;
|
||||||
|
if (load) {
|
||||||
|
this.load();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
changePayment() {
|
changePayment() {
|
||||||
|
this.showAdjustPayment = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
closePayment(load: boolean) {
|
||||||
|
this.showAdjustPayment = false;
|
||||||
|
if (load) {
|
||||||
|
this.load();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get subscriptionMarkedForCancel() {
|
get subscriptionMarkedForCancel() {
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 17 KiB |
@@ -1404,5 +1404,14 @@
|
|||||||
"example": "5"
|
"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."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,6 +132,11 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card-body-header {
|
||||||
|
font-size: $h3-font-size * 1.12;
|
||||||
|
@extend .mb-4
|
||||||
|
}
|
||||||
|
|
||||||
.card ul.fa-ul.card-ul {
|
.card ul.fa-ul.card-ul {
|
||||||
margin-left: 1.9em;
|
margin-left: 1.9em;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user