mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 08:13:42 +00:00
* Added select-payment-method.component in shared lib Because we're going to be implementing the same functionality for providers and orgs/users, I wanted to start moving some of this shared functionality into libs so it can be accessed in both web and bit-web. Additionally, the Stripe and Braintree functionality has been moved into their own services for more central management. * Added generalized manage-tax-information component to shared lib * Added generalized add-account-credit-dialog component to shared libs * Added generalized verify-bank-account component to shared libs * Added dialog for selection of provider payment method * Added provider-payment-method component * Added provider-payment-method component to provider layout
160 lines
4.6 KiB
TypeScript
160 lines
4.6 KiB
TypeScript
import { Component, Input, OnDestroy, OnInit } from "@angular/core";
|
|
import { FormBuilder, Validators } from "@angular/forms";
|
|
import { Subject } from "rxjs";
|
|
import { takeUntil } from "rxjs/operators";
|
|
|
|
import {
|
|
BillingApiServiceAbstraction,
|
|
BraintreeServiceAbstraction,
|
|
StripeServiceAbstraction,
|
|
} from "@bitwarden/common/billing/abstractions";
|
|
import { PaymentMethodType } from "@bitwarden/common/billing/enums";
|
|
import { TokenizedPaymentMethod } from "@bitwarden/common/billing/models/domain";
|
|
|
|
@Component({
|
|
selector: "app-select-payment-method",
|
|
templateUrl: "./select-payment-method.component.html",
|
|
})
|
|
export class SelectPaymentMethodComponent implements OnInit, OnDestroy {
|
|
@Input() protected showAccountCredit: boolean = true;
|
|
@Input() protected showBankAccount: boolean = true;
|
|
@Input() protected showPayPal: boolean = true;
|
|
@Input() private startWith: PaymentMethodType = PaymentMethodType.Card;
|
|
@Input() protected onSubmit: (tokenizedPaymentMethod: TokenizedPaymentMethod) => Promise<void>;
|
|
|
|
private destroy$ = new Subject<void>();
|
|
|
|
protected formGroup = this.formBuilder.group({
|
|
paymentMethod: [this.startWith],
|
|
bankInformation: this.formBuilder.group({
|
|
routingNumber: ["", [Validators.required]],
|
|
accountNumber: ["", [Validators.required]],
|
|
accountHolderName: ["", [Validators.required]],
|
|
accountHolderType: ["", [Validators.required]],
|
|
}),
|
|
});
|
|
protected PaymentMethodType = PaymentMethodType;
|
|
|
|
constructor(
|
|
private billingApiService: BillingApiServiceAbstraction,
|
|
private braintreeService: BraintreeServiceAbstraction,
|
|
private formBuilder: FormBuilder,
|
|
private stripeService: StripeServiceAbstraction,
|
|
) {}
|
|
|
|
async tokenizePaymentMethod(): Promise<TokenizedPaymentMethod> {
|
|
const type = this.selected;
|
|
|
|
if (this.usingStripe) {
|
|
const clientSecret = await this.billingApiService.createSetupIntent(type);
|
|
|
|
if (this.usingBankAccount) {
|
|
const token = await this.stripeService.setupBankAccountPaymentMethod(clientSecret, {
|
|
accountHolderName: this.formGroup.value.bankInformation.accountHolderName,
|
|
routingNumber: this.formGroup.value.bankInformation.routingNumber,
|
|
accountNumber: this.formGroup.value.bankInformation.accountNumber,
|
|
accountHolderType: this.formGroup.value.bankInformation.accountHolderType,
|
|
});
|
|
return {
|
|
type,
|
|
token,
|
|
};
|
|
}
|
|
|
|
if (this.usingCard) {
|
|
const token = await this.stripeService.setupCardPaymentMethod(clientSecret);
|
|
return {
|
|
type,
|
|
token,
|
|
};
|
|
}
|
|
}
|
|
|
|
if (this.usingPayPal) {
|
|
const token = await this.braintreeService.requestPaymentMethod();
|
|
return {
|
|
type,
|
|
token,
|
|
};
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
submit = async () => {
|
|
const tokenizedPaymentMethod = await this.tokenizePaymentMethod();
|
|
await this.onSubmit(tokenizedPaymentMethod);
|
|
};
|
|
|
|
ngOnInit(): void {
|
|
this.stripeService.loadStripe(
|
|
{
|
|
cardNumber: "#stripe-card-number",
|
|
cardExpiry: "#stripe-card-expiry",
|
|
cardCvc: "#stripe-card-cvc",
|
|
},
|
|
this.startWith === PaymentMethodType.Card,
|
|
);
|
|
|
|
if (this.showPayPal) {
|
|
this.braintreeService.loadBraintree(
|
|
"#braintree-container",
|
|
this.startWith === PaymentMethodType.PayPal,
|
|
);
|
|
}
|
|
|
|
this.formGroup
|
|
.get("paymentMethod")
|
|
.valueChanges.pipe(takeUntil(this.destroy$))
|
|
.subscribe((type) => {
|
|
this.onPaymentMethodChange(type);
|
|
});
|
|
}
|
|
|
|
ngOnDestroy(): void {
|
|
this.destroy$.next();
|
|
this.destroy$.complete();
|
|
this.stripeService.unloadStripe();
|
|
if (this.showPayPal) {
|
|
this.braintreeService.unloadBraintree();
|
|
}
|
|
}
|
|
|
|
private onPaymentMethodChange(type: PaymentMethodType): void {
|
|
switch (type) {
|
|
case PaymentMethodType.Card: {
|
|
this.stripeService.mountElements();
|
|
break;
|
|
}
|
|
case PaymentMethodType.PayPal: {
|
|
this.braintreeService.createDropin();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private get selected(): PaymentMethodType {
|
|
return this.formGroup.value.paymentMethod;
|
|
}
|
|
|
|
protected get usingAccountCredit(): boolean {
|
|
return this.selected === PaymentMethodType.Credit;
|
|
}
|
|
|
|
protected get usingBankAccount(): boolean {
|
|
return this.selected === PaymentMethodType.BankAccount;
|
|
}
|
|
|
|
protected get usingCard(): boolean {
|
|
return this.selected === PaymentMethodType.Card;
|
|
}
|
|
|
|
protected get usingPayPal(): boolean {
|
|
return this.selected === PaymentMethodType.PayPal;
|
|
}
|
|
|
|
private get usingStripe(): boolean {
|
|
return this.usingBankAccount || this.usingCard;
|
|
}
|
|
}
|