mirror of
https://github.com/bitwarden/browser.git
synced 2024-12-22 16:29:09 +01:00
PM-5019 Migrate Adjust Payment component (#8383)
* PM-5019 Migrated Adjust Payment component * PM-5019 Migrated Adjust Payment dialog component * PM-5019 Removing type any * PM-5019 Addressed review comments * PM-5019 Included deleted line space
This commit is contained in:
parent
d6f2965367
commit
f5198e86fd
@ -0,0 +1,25 @@
|
|||||||
|
<form [formGroup]="formGroup" [bitSubmit]="submit">
|
||||||
|
<bit-dialog
|
||||||
|
dialogSize="large"
|
||||||
|
[title]="(currentType != null ? 'changePaymentMethod' : 'addPaymentMethod') | i18n"
|
||||||
|
>
|
||||||
|
<ng-container bitDialogContent>
|
||||||
|
<app-payment [hideBank]="!organizationId" [hideCredit]="true"></app-payment>
|
||||||
|
<app-tax-info (onCountryChanged)="changeCountry()"></app-tax-info>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container bitDialogFooter>
|
||||||
|
<button type="submit" bitButton bitFormButton buttonType="primary">
|
||||||
|
{{ "submit" | i18n }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
bitButton
|
||||||
|
bitFormButton
|
||||||
|
buttonType="secondary"
|
||||||
|
[bitDialogClose]="DialogResult.Cancelled"
|
||||||
|
>
|
||||||
|
{{ "cancel" | i18n }}
|
||||||
|
</button>
|
||||||
|
</ng-container>
|
||||||
|
</bit-dialog>
|
||||||
|
</form>
|
@ -0,0 +1,110 @@
|
|||||||
|
import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog";
|
||||||
|
import { Component, Inject, ViewChild } from "@angular/core";
|
||||||
|
import { FormGroup } from "@angular/forms";
|
||||||
|
|
||||||
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
|
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||||
|
import { PaymentMethodWarningsServiceAbstraction as PaymentMethodWarningService } from "@bitwarden/common/billing/abstractions/payment-method-warnings-service.abstraction";
|
||||||
|
import { PaymentMethodType } from "@bitwarden/common/billing/enums";
|
||||||
|
import { PaymentRequest } from "@bitwarden/common/billing/models/request/payment.request";
|
||||||
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
|
import { DialogService } from "@bitwarden/components";
|
||||||
|
|
||||||
|
import { PaymentComponent } from "./payment.component";
|
||||||
|
import { TaxInfoComponent } from "./tax-info.component";
|
||||||
|
|
||||||
|
export interface AdjustPaymentDialogData {
|
||||||
|
organizationId: string;
|
||||||
|
currentType: PaymentMethodType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum AdjustPaymentDialogResult {
|
||||||
|
Adjusted = "adjusted",
|
||||||
|
Cancelled = "cancelled",
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: "adjust-payment-dialog.component.html",
|
||||||
|
})
|
||||||
|
export class AdjustPaymentDialogComponent {
|
||||||
|
@ViewChild(PaymentComponent, { static: true }) paymentComponent: PaymentComponent;
|
||||||
|
@ViewChild(TaxInfoComponent, { static: true }) taxInfoComponent: TaxInfoComponent;
|
||||||
|
|
||||||
|
organizationId: string;
|
||||||
|
currentType: PaymentMethodType;
|
||||||
|
paymentMethodType = PaymentMethodType;
|
||||||
|
|
||||||
|
protected DialogResult = AdjustPaymentDialogResult;
|
||||||
|
protected formGroup = new FormGroup({});
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private dialogRef: DialogRef,
|
||||||
|
@Inject(DIALOG_DATA) protected data: AdjustPaymentDialogData,
|
||||||
|
private apiService: ApiService,
|
||||||
|
private i18nService: I18nService,
|
||||||
|
private platformUtilsService: PlatformUtilsService,
|
||||||
|
private logService: LogService,
|
||||||
|
private organizationApiService: OrganizationApiServiceAbstraction,
|
||||||
|
private paymentMethodWarningService: PaymentMethodWarningService,
|
||||||
|
) {
|
||||||
|
this.organizationId = data.organizationId;
|
||||||
|
this.currentType = data.currentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
submit = async () => {
|
||||||
|
const request = new PaymentRequest();
|
||||||
|
const response = this.paymentComponent.createPaymentToken().then((result) => {
|
||||||
|
request.paymentToken = result[0];
|
||||||
|
request.paymentMethodType = result[1];
|
||||||
|
request.postalCode = this.taxInfoComponent.taxInfo.postalCode;
|
||||||
|
request.country = this.taxInfoComponent.taxInfo.country;
|
||||||
|
if (this.organizationId == null) {
|
||||||
|
return this.apiService.postAccountPayment(request);
|
||||||
|
} else {
|
||||||
|
request.taxId = this.taxInfoComponent.taxInfo.taxId;
|
||||||
|
request.state = this.taxInfoComponent.taxInfo.state;
|
||||||
|
request.line1 = this.taxInfoComponent.taxInfo.line1;
|
||||||
|
request.line2 = this.taxInfoComponent.taxInfo.line2;
|
||||||
|
request.city = this.taxInfoComponent.taxInfo.city;
|
||||||
|
request.state = this.taxInfoComponent.taxInfo.state;
|
||||||
|
return this.organizationApiService.updatePayment(this.organizationId, request);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await response;
|
||||||
|
if (this.organizationId) {
|
||||||
|
await this.paymentMethodWarningService.removeSubscriptionRisk(this.organizationId);
|
||||||
|
}
|
||||||
|
this.platformUtilsService.showToast(
|
||||||
|
"success",
|
||||||
|
null,
|
||||||
|
this.i18nService.t("updatedPaymentMethod"),
|
||||||
|
);
|
||||||
|
this.dialogRef.close(AdjustPaymentDialogResult.Adjusted);
|
||||||
|
};
|
||||||
|
|
||||||
|
changeCountry() {
|
||||||
|
if (this.taxInfoComponent.taxInfo.country === "US") {
|
||||||
|
this.paymentComponent.hideBank = !this.organizationId;
|
||||||
|
} else {
|
||||||
|
this.paymentComponent.hideBank = true;
|
||||||
|
if (this.paymentComponent.method === PaymentMethodType.BankAccount) {
|
||||||
|
this.paymentComponent.method = PaymentMethodType.Card;
|
||||||
|
this.paymentComponent.changeMethod();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strongly typed helper to open a AdjustPaymentDialog
|
||||||
|
* @param dialogService Instance of the dialog service that will be used to open the dialog
|
||||||
|
* @param config Configuration for the dialog
|
||||||
|
*/
|
||||||
|
export function openAdjustPaymentDialog(
|
||||||
|
dialogService: DialogService,
|
||||||
|
config: DialogConfig<AdjustPaymentDialogData>,
|
||||||
|
) {
|
||||||
|
return dialogService.open<AdjustPaymentDialogResult>(AdjustPaymentDialogComponent, config);
|
||||||
|
}
|
@ -1,19 +0,0 @@
|
|||||||
<form #form class="card" (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate>
|
|
||||||
<div class="card-body">
|
|
||||||
<button type="button" class="close" appA11yTitle="{{ 'cancel' | i18n }}" (click)="cancel()">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
<h3 class="card-body-header">
|
|
||||||
{{ (currentType != null ? "changePaymentMethod" : "addPaymentMethod") | i18n }}
|
|
||||||
</h3>
|
|
||||||
<app-payment [hideBank]="!organizationId" [hideCredit]="true"></app-payment>
|
|
||||||
<app-tax-info (onCountryChanged)="changeCountry()"></app-tax-info>
|
|
||||||
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading">
|
|
||||||
<i class="bwi bwi-spinner bwi-spin" title="{{ 'loading' | i18n }}" aria-hidden="true"></i>
|
|
||||||
<span>{{ "submit" | i18n }}</span>
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-outline-secondary" (click)="cancel()">
|
|
||||||
{{ "cancel" | i18n }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
@ -1,90 +0,0 @@
|
|||||||
import { Component, EventEmitter, Input, Output, ViewChild } from "@angular/core";
|
|
||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
|
||||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
|
||||||
import { PaymentMethodWarningsServiceAbstraction as PaymentMethodWarningService } from "@bitwarden/common/billing/abstractions/payment-method-warnings-service.abstraction";
|
|
||||||
import { PaymentMethodType } from "@bitwarden/common/billing/enums";
|
|
||||||
import { PaymentRequest } from "@bitwarden/common/billing/models/request/payment.request";
|
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
|
||||||
|
|
||||||
import { PaymentComponent } from "./payment.component";
|
|
||||||
import { TaxInfoComponent } from "./tax-info.component";
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: "app-adjust-payment",
|
|
||||||
templateUrl: "adjust-payment.component.html",
|
|
||||||
})
|
|
||||||
export class AdjustPaymentComponent {
|
|
||||||
@ViewChild(PaymentComponent, { static: true }) paymentComponent: PaymentComponent;
|
|
||||||
@ViewChild(TaxInfoComponent, { static: true }) taxInfoComponent: TaxInfoComponent;
|
|
||||||
|
|
||||||
@Input() currentType?: PaymentMethodType;
|
|
||||||
@Input() organizationId: string;
|
|
||||||
@Output() onAdjusted = new EventEmitter();
|
|
||||||
@Output() onCanceled = new EventEmitter();
|
|
||||||
|
|
||||||
paymentMethodType = PaymentMethodType;
|
|
||||||
formPromise: Promise<void>;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private apiService: ApiService,
|
|
||||||
private i18nService: I18nService,
|
|
||||||
private platformUtilsService: PlatformUtilsService,
|
|
||||||
private logService: LogService,
|
|
||||||
private organizationApiService: OrganizationApiServiceAbstraction,
|
|
||||||
private paymentMethodWarningService: PaymentMethodWarningService,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async submit() {
|
|
||||||
try {
|
|
||||||
const request = new PaymentRequest();
|
|
||||||
this.formPromise = this.paymentComponent.createPaymentToken().then((result) => {
|
|
||||||
request.paymentToken = result[0];
|
|
||||||
request.paymentMethodType = result[1];
|
|
||||||
request.postalCode = this.taxInfoComponent.taxInfo.postalCode;
|
|
||||||
request.country = this.taxInfoComponent.taxInfo.country;
|
|
||||||
if (this.organizationId == null) {
|
|
||||||
return this.apiService.postAccountPayment(request);
|
|
||||||
} else {
|
|
||||||
request.taxId = this.taxInfoComponent.taxInfo.taxId;
|
|
||||||
request.state = this.taxInfoComponent.taxInfo.state;
|
|
||||||
request.line1 = this.taxInfoComponent.taxInfo.line1;
|
|
||||||
request.line2 = this.taxInfoComponent.taxInfo.line2;
|
|
||||||
request.city = this.taxInfoComponent.taxInfo.city;
|
|
||||||
request.state = this.taxInfoComponent.taxInfo.state;
|
|
||||||
return this.organizationApiService.updatePayment(this.organizationId, request);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
await this.formPromise;
|
|
||||||
if (this.organizationId) {
|
|
||||||
await this.paymentMethodWarningService.removeSubscriptionRisk(this.organizationId);
|
|
||||||
}
|
|
||||||
this.platformUtilsService.showToast(
|
|
||||||
"success",
|
|
||||||
null,
|
|
||||||
this.i18nService.t("updatedPaymentMethod"),
|
|
||||||
);
|
|
||||||
this.onAdjusted.emit();
|
|
||||||
} catch (e) {
|
|
||||||
this.logService.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cancel() {
|
|
||||||
this.onCanceled.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
changeCountry() {
|
|
||||||
if (this.taxInfoComponent.taxInfo.country === "US") {
|
|
||||||
this.paymentComponent.hideBank = !this.organizationId;
|
|
||||||
} else {
|
|
||||||
this.paymentComponent.hideBank = true;
|
|
||||||
if (this.paymentComponent.method === PaymentMethodType.BankAccount) {
|
|
||||||
this.paymentComponent.method = PaymentMethodType.Card;
|
|
||||||
this.paymentComponent.changeMethod();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,7 +4,7 @@ import { HeaderModule } from "../../layouts/header/header.module";
|
|||||||
import { SharedModule } from "../../shared";
|
import { SharedModule } from "../../shared";
|
||||||
|
|
||||||
import { AddCreditComponent } from "./add-credit.component";
|
import { AddCreditComponent } from "./add-credit.component";
|
||||||
import { AdjustPaymentComponent } from "./adjust-payment.component";
|
import { AdjustPaymentDialogComponent } from "./adjust-payment-dialog.component";
|
||||||
import { AdjustStorageComponent } from "./adjust-storage.component";
|
import { AdjustStorageComponent } from "./adjust-storage.component";
|
||||||
import { BillingHistoryComponent } from "./billing-history.component";
|
import { BillingHistoryComponent } from "./billing-history.component";
|
||||||
import { OffboardingSurveyComponent } from "./offboarding-survey.component";
|
import { OffboardingSurveyComponent } from "./offboarding-survey.component";
|
||||||
@ -18,7 +18,7 @@ import { UpdateLicenseComponent } from "./update-license.component";
|
|||||||
imports: [SharedModule, PaymentComponent, TaxInfoComponent, HeaderModule],
|
imports: [SharedModule, PaymentComponent, TaxInfoComponent, HeaderModule],
|
||||||
declarations: [
|
declarations: [
|
||||||
AddCreditComponent,
|
AddCreditComponent,
|
||||||
AdjustPaymentComponent,
|
AdjustPaymentDialogComponent,
|
||||||
AdjustStorageComponent,
|
AdjustStorageComponent,
|
||||||
BillingHistoryComponent,
|
BillingHistoryComponent,
|
||||||
PaymentMethodComponent,
|
PaymentMethodComponent,
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
<bit-container>
|
<bit-container>
|
||||||
<div class="tabbed-header" *ngIf="!organizationId">
|
<div class="tabbed-header" *ngIf="!organizationId">
|
||||||
<!-- TODO: Organization and individual should use different "page" components -->
|
<!--TODO: Organization and individual should use different "page" components -->
|
||||||
<h1>{{ "paymentMethod" | i18n }}</h1>
|
<h1>{{ "paymentMethod" | i18n }}</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -102,23 +102,9 @@
|
|||||||
{{ paymentSource.description }}
|
{{ paymentSource.description }}
|
||||||
</p>
|
</p>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<button
|
<button type="button" bitButton buttonType="secondary" [bitAction]="changePayment">
|
||||||
type="button"
|
|
||||||
bitButton
|
|
||||||
buttonType="secondary"
|
|
||||||
(click)="changePayment()"
|
|
||||||
*ngIf="!showAdjustPayment"
|
|
||||||
>
|
|
||||||
{{ (paymentSource ? "changePaymentMethod" : "addPaymentMethod") | i18n }}
|
{{ (paymentSource ? "changePaymentMethod" : "addPaymentMethod") | i18n }}
|
||||||
</button>
|
</button>
|
||||||
<app-adjust-payment
|
|
||||||
[organizationId]="organizationId"
|
|
||||||
[currentType]="paymentSource != null ? paymentSource.type : null"
|
|
||||||
(onAdjusted)="closePayment(true)"
|
|
||||||
(onCanceled)="closePayment(false)"
|
|
||||||
*ngIf="showAdjustPayment"
|
|
||||||
>
|
|
||||||
</app-adjust-payment>
|
|
||||||
<p *ngIf="isUnpaid">{{ "paymentChargedWithUnpaidSubscription" | i18n }}</p>
|
<p *ngIf="isUnpaid">{{ "paymentChargedWithUnpaidSubscription" | i18n }}</p>
|
||||||
<ng-container *ngIf="forOrganization">
|
<ng-container *ngIf="forOrganization">
|
||||||
<h2 class="spaced-header">{{ "taxInformation" | i18n }}</h2>
|
<h2 class="spaced-header">{{ "taxInformation" | i18n }}</h2>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { Component, OnInit, ViewChild } from "@angular/core";
|
import { Component, OnInit, ViewChild } from "@angular/core";
|
||||||
import { FormBuilder, FormControl, Validators } from "@angular/forms";
|
import { FormBuilder, FormControl, Validators } from "@angular/forms";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
|
import { lastValueFrom } from "rxjs";
|
||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||||
@ -14,6 +15,10 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
|
|||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
|
|
||||||
|
import {
|
||||||
|
AdjustPaymentDialogResult,
|
||||||
|
openAdjustPaymentDialog,
|
||||||
|
} from "./adjust-payment-dialog.component";
|
||||||
import { TaxInfoComponent } from "./tax-info.component";
|
import { TaxInfoComponent } from "./tax-info.component";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -25,7 +30,6 @@ export class PaymentMethodComponent implements OnInit {
|
|||||||
|
|
||||||
loading = false;
|
loading = false;
|
||||||
firstLoaded = false;
|
firstLoaded = false;
|
||||||
showAdjustPayment = false;
|
|
||||||
showAddCredit = false;
|
showAddCredit = false;
|
||||||
billing: BillingPaymentResponse;
|
billing: BillingPaymentResponse;
|
||||||
org: OrganizationSubscriptionResponse;
|
org: OrganizationSubscriptionResponse;
|
||||||
@ -120,18 +124,18 @@ export class PaymentMethodComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
changePayment() {
|
changePayment = async () => {
|
||||||
this.showAdjustPayment = true;
|
const dialogRef = openAdjustPaymentDialog(this.dialogService, {
|
||||||
}
|
data: {
|
||||||
|
organizationId: this.organizationId,
|
||||||
closePayment(load: boolean) {
|
currentType: this.paymentSource !== null ? this.paymentSource.type : null,
|
||||||
this.showAdjustPayment = false;
|
},
|
||||||
if (load) {
|
});
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
const result = await lastValueFrom(dialogRef.closed);
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
if (result === AdjustPaymentDialogResult.Adjusted) {
|
||||||
this.load();
|
await this.load();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
async verifyBank() {
|
async verifyBank() {
|
||||||
if (this.loading || !this.forOrganization) {
|
if (this.loading || !this.forOrganization) {
|
||||||
|
Loading…
Reference in New Issue
Block a user