diff --git a/jslib b/jslib index 393f6c9c20..e28e820286 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit 393f6c9c20fb7eded5008b65242ea44e69bc349c +Subproject commit e28e820286870df0111bd4feb8a219a3ae360ba7 diff --git a/src/app/settings/organization-plans.component.html b/src/app/settings/organization-plans.component.html index 77b0b550ba..b454e31052 100644 --- a/src/app/settings/organization-plans.component.html +++ b/src/app/settings/organization-plans.component.html @@ -203,6 +203,9 @@

{{'paymentInformation' | i18n}}

+ + + {{'paymentCharged' | i18n : (interval | i18n) }} diff --git a/src/app/settings/organization-plans.component.ts b/src/app/settings/organization-plans.component.ts index d9c6a494fc..20ad1b26d8 100644 --- a/src/app/settings/organization-plans.component.ts +++ b/src/app/settings/organization-plans.component.ts @@ -169,7 +169,10 @@ export class OrganizationPlansComponent { } else { request.planType = this.plans[this.plan].annualPlanType; } - await this.apiService.postOrganizationUpgrade(this.organizationId, request); + const result = await this.apiService.postOrganizationUpgrade(this.organizationId, request); + if (!result.success && result.paymentIntentClientSecret != null) { + await this.paymentComponent.handleStripeCardPayment(result.paymentIntentClientSecret, null); + } orgId = this.organizationId; } diff --git a/src/app/settings/payment.component.html b/src/app/settings/payment.component.html index 242da80389..1ba929ecbf 100644 --- a/src/app/settings/payment.component.html +++ b/src/app/settings/payment.component.html @@ -1,4 +1,4 @@ -
+
@@ -24,7 +24,7 @@ {{'accountCredit' | i18n}}
- +
@@ -50,7 +50,7 @@
- + {{'verifyBankAccountInitialDesc' | i18n}} {{'verifyBankAccountFailureWarning' | i18n}} @@ -81,13 +81,13 @@
- +
{{'paypalClickSubmit' | i18n}}
- + {{'makeSureEnoughCredit' | i18n}} diff --git a/src/app/settings/payment.component.ts b/src/app/settings/payment.component.ts index 90a4eb0ff1..1aae8b7b3e 100644 --- a/src/app/settings/payment.component.ts +++ b/src/app/settings/payment.component.ts @@ -6,6 +6,7 @@ import { import { PaymentMethodType } from 'jslib/enums/paymentMethodType'; +import { ApiService } from 'jslib/abstractions/api.service'; import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; import { WebConstants } from '../../services/webConstants'; @@ -34,6 +35,7 @@ const StripeElementClasses = { templateUrl: 'payment.component.html', }) export class PaymentComponent implements OnInit { + @Input() showMethods = true; @Input() showOptions = true; @Input() method = PaymentMethodType.Card; @Input() hideBank = false; @@ -60,7 +62,7 @@ export class PaymentComponent implements OnInit { private stripeCardExpiryElement: any = null; private stripeCardCvcElement: any = null; - constructor(private platformUtilsService: PlatformUtilsService) { + constructor(private platformUtilsService: PlatformUtilsService, private apiService: ApiService) { this.stripeScript = window.document.createElement('script'); this.stripeScript.src = 'https://js.stripe.com/v3/'; this.stripeScript.async = true; @@ -162,30 +164,60 @@ export class PaymentComponent implements OnInit { reject(err.message); }); } else if (this.method === PaymentMethodType.Card || this.method === PaymentMethodType.BankAccount) { - let sourceObj: any = null; - let createObj: any = null; if (this.method === PaymentMethodType.Card) { - sourceObj = this.stripeCardNumberElement; + this.apiService.postSetupPayment().then((clientSecret) => + this.stripe.handleCardSetup(clientSecret, this.stripeCardNumberElement)) + .then((result: any) => { + if (result.error) { + reject(result.error.message); + } else if (result.setupIntent && result.setupIntent.status === 'succeeded') { + resolve([result.setupIntent.payment_method, this.method]); + } else { + reject(); + } + }); } else { - sourceObj = 'bank_account'; - createObj = this.bank; + this.stripe.createToken('bank_account', this.bank).then((result: any) => { + if (result.error) { + reject(result.error.message); + } else if (result.token && result.token.id != null) { + resolve([result.token.id, this.method]); + } else { + reject(); + } + }); } - this.stripe.createToken(sourceObj, createObj).then((result: any) => { - if (result.error) { - reject(result.error.message); - } else if (result.token && result.token.id != null) { - resolve([result.token.id, this.method]); - } else { - reject(); - } - }); } }); } + handleStripeCardPayment(clientSecret: string, successCallback: () => Promise): Promise { + return new Promise((resolve, reject) => { + if (this.showMethods && this.stripeCardNumberElement == null) { + reject(); + return; + } + const handleCardPayment = () => this.showMethods ? + this.stripe.handleCardPayment(clientSecret, this.stripeCardNumberElement) : + this.stripe.handleCardPayment(clientSecret); + return handleCardPayment().then(async (result: any) => { + if (result.error) { + reject(result.error.message); + } else if (result.paymentIntent && result.paymentIntent.status === 'succeeded') { + if (successCallback != null) { + await successCallback(); + } + resolve(); + } else { + reject(); + } + }); + }); + } + private setStripeElement() { window.setTimeout(() => { - if (this.method === PaymentMethodType.Card) { + if (this.showMethods && this.method === PaymentMethodType.Card) { if (this.stripeCardNumberElement == null) { this.stripeCardNumberElement = this.stripeElements.create('cardNumber', { style: StripeElementStyle, diff --git a/src/app/settings/premium.component.ts b/src/app/settings/premium.component.ts index 310d937c18..01ee3d1e21 100644 --- a/src/app/settings/premium.component.ts +++ b/src/app/settings/premium.component.ts @@ -84,8 +84,13 @@ export class PremiumComponent implements OnInit { } fd.append('additionalStorageGb', (this.additionalStorage || 0).toString()); return this.apiService.postPremium(fd); - }).then(() => { - return this.finalizePremium(); + }).then((paymentResponse) => { + if (!paymentResponse.success && paymentResponse.paymentIntentClientSecret != null) { + return this.paymentComponent.handleStripeCardPayment(paymentResponse.paymentIntentClientSecret, + () => this.finalizePremium()); + } else { + return this.finalizePremium(); + } }); } await this.formPromise;