diff --git a/demo-angular/app/demo/intent.component.ts b/demo-angular/app/demo/intent.component.ts index 8ede374..0401c19 100644 --- a/demo-angular/app/demo/intent.component.ts +++ b/demo-angular/app/demo/intent.component.ts @@ -1,11 +1,9 @@ -import { ChangeDetectorRef, Component, ViewContainerRef, Input } from "@angular/core"; +import { ChangeDetectorRef, Component, ViewContainerRef } from "@angular/core"; import { ModalDialogService } from "nativescript-angular/modal-dialog"; -import { CreditCardView, PaymentMethod, Stripe, Token, StripePaymentIntentParams, StripePaymentIntent } from "nativescript-stripe"; -import { isAndroid } from "tns-core-modules/platform"; -import { publishableKey, StripeService } from "./stripe.service"; +import { Card, CreditCardView, PaymentMethod, Stripe, StripePaymentIntentParams } from "nativescript-stripe"; import { alert } from "tns-core-modules/ui/dialogs"; - import { ItentModalComponent } from "./intent-modal.component"; +import { publishableKey, StripeService } from "./stripe.service"; @Component({ selector: "stp-intent", @@ -43,88 +41,139 @@ export class IntentComponent { } registerCard(cardView: CreditCardView) { + console.log("registerCard"); this._setStatus("Create Setup Intent..."); - this.stripeService.createSetupIntent().then((intent) => { - - this._setStatus("Create Payment Method..."); - this.stripe.createPaymentMethod(cardView.card, (error, pm) => { - if (error) return this._displayError(error); - this._setStatus("Confirm Setup Intent..."); - this.stripe.confirmSetupIntent(pm.id, intent.secret, (error, setupIntent) => { - if (error) this._displayError(error); - this._setStatus(`Setup Intent Status => ${setupIntent.status}`); - }); - }); - }); + this.stripeService.createSetupIntent() + .then(intent => this._createPaymentMethod(cardView.card) + .then(pm => this._confirmSetupIntent(pm.id, intent.secret)) + .then(setupIntent => this._setStatus(`Setup Intent Status => ${setupIntent.status}`))) + .catch(err => this._displayError(err, "registerCard")); } // Authenticate and charge on the UI - // https://stripe.com/docs/payments/payment-intents/ios#automatic-confirmation-ios + // https://stripe.com/docs/payments/payment-intents/ios automaticConfirmPayment(cardView: CreditCardView) { - this._setStatus("Create Payment Method..."); - this.stripe.createPaymentMethod(cardView.card, (error, pm) => { - if (error) return this._displayError(error); - this._createPaymentIntent().then(p => { - const piParams = new StripePaymentIntentParams(); - piParams.paymentMethodId = pm.id; - piParams.clientSecret = p.secret; - this._confirmPaymentIntent(piParams); - }); - }); + console.log("automaticConfirmPayment"); + this._createPaymentMethod(cardView.card) + .then(pm => this._createPaymentIntent() + .then(pi => this._confirmPaymentIntent(pm.id, pi.secret)) + .then(pi => this._setStatus(`Payment Status: ${pi.status}`))) + .catch(err => this._displayError(err, "automaticConfirmPayment")); } // Authenticate on the UI only, confirm charge on back-end - // https://stripe.com/docs/payments/payment-intents/ios#handle-authentication-manual + // https://stripe.com/docs/payments/payment-intents/ios-manual manualConfirmPayment(cardView: CreditCardView) { - this._setStatus("Create Payment Method..."); - this.stripe.createPaymentMethod(cardView.card, (error, pm) => { - if (error) return this._displayError(error); - - this._setStatus("Create Payment Intent..."); - this.stripeService.capturePayment(pm.id, this._item.price).then(({ secret }) => { - - this._setStatus("Authenticate Payment Intent..."); - this.stripe.authenticatePaymentIntent(secret, null, (error, pintent) => { - if (error) return this._displayError(error); - if (pintent.requiresConfirmation) { - this._setStatus("Confirm Payment Intent..."); - this.stripeService.confirmPaymentIntent(pintent.id).then(response => { - this._setStatus(`Payment Intent Processed: ${JSON.stringify(response)}`); - }); - } else { - // Not ready to be processed by backend - this._setStatus(`Payment Status: ${pintent.status}`); - } - }); - }); - }); + console.log("manualConfirmPayment"); + this._createPaymentMethod(cardView.card) + .then(pm => this._createManualPaymentIntent(pm.id)) + .then(pi => { + if (pi.requires_action) return this._authenticatePaymentIntent(pi.secret); + return pi; + }) + .then(pi => { + if (pi.requiresConfirmation) { + return this._confirmManualPaymentIntent(pi.id) + .then(response => `Payment Intent Processed: ${JSON.stringify(response)}`); + } else if (!pi.status) { + pi.status = pi.success ? "success" : "failed"; + } + return `Payment Status: ${pi.status}`; + }) + .then(status => this._setStatus(status)) + .catch(err => this._displayError(err, "manualConfirmPayment")); } /* - * Private + * Private. Convert callback-based calls to Stripe with Promises. */ + private _createPaymentMethod(card: Card): Promise { + this._setStatus(`Create Payment Method (${card.brand} ${card.last4})...`); + return new Promise((resolve, reject) => { + this.stripe.createPaymentMethod(card, (error, pm) => { + if (error) return reject(error); + console.log("Stripe.createPaymentMethod response:", pm.id); + resolve(pm); + }); + }); + } + private _createPaymentIntent(): Promise { this._setStatus("Create Payment Intent..."); - return this.stripeService.createPaymentIntent(this._item.price, this._item.currency); + return this.stripeService.createPaymentIntent(this._item.price, this._item.currency) + .then(response => { + console.log('StripeService.createPaymentIntent response:', response); + return response; + }); } - private _confirmPaymentIntent(piParams) { - this._setStatus("Confirm Payment Intent..."); - this.stripe.confirmPaymentIntent(piParams, (error, pintent) => { - if (error) return this._displayError(error); - this._setStatus(`Payment Status: ${pintent.status}`); + private _createManualPaymentIntent(pmId: string): Promise { + this._setStatus(`Create Manual Payment Intent (${pmId})...`); + return this.stripeService.capturePayment(pmId, this._item.price) + .then(response => { + console.log('StripeService.capturePayment response:', response); + return response; + }); + } + + private _confirmManualPaymentIntent(id: string): Promise { + this._setStatus("Confirm Manual Payment Intent..."); + return this.stripeService.confirmPaymentIntent(id) + .then(response => { + console.log('StripeService.confirmPaymentIntent response:', response); + return response; + }); + } + + private _confirmSetupIntent(id: string, secret: string): Promise { + this._setStatus(`Confirm Setup Intent (${id}, ${secret})...`); + return new Promise((resolve, reject) => { + this.stripe.confirmSetupIntent(id, secret, (error, setupIntent) => { + if (error) return reject(error); + console.log("Stripe.confirmSetupIntent response:", setupIntent.id, setupIntent.status); + resolve(setupIntent); + }); + }); + } + + private _confirmPaymentIntent(pmId: string, secret: string): Promise { + this._setStatus(`Confirm Payment Intent (${pmId}, ${secret})...`); + const piParams = new StripePaymentIntentParams(); + piParams.paymentMethodId = pmId; + piParams.clientSecret = secret; + return new Promise((resolve, reject) => { + this.stripe.confirmPaymentIntent(piParams, (error, pintent) => { + if (error) return reject(error); + console.log("Stripe.confirmPaymentIntent response:", pintent.id, pintent.status); + resolve(pintent); + }); + }); + } + + private _authenticatePaymentIntent(secret: string): Promise { + this._setStatus(`Authenticate Payment Intent (${secret})...`); + return new Promise((resolve, reject) => { + this.stripe.authenticatePaymentIntent(secret, null, (error, pintent) => { + if (error) return reject(error); + console.log("Stripe.authenticatePaymentIntent response:", JSON.stringify(pintent)); + resolve(pintent); + }); }); } - private _setStatus(message) { + private _setStatus(message: string) { + console.log(message); this.status = message; this.changeDetectionRef.detectChanges(); } - private _displayError(message) { + private _displayError(error: Error, operation: string) { + const msg = "Error during " + operation; + console.log(msg, error.message, error.stack); alert({ - message, + title: msg, + message: error.message, okButtonText: "OK" }).then(() => this._setStatus(null)); } diff --git a/demo-angular/app/demo/stripe.service.ts b/demo-angular/app/demo/stripe.service.ts index 9f70e2b..010742b 100644 --- a/demo-angular/app/demo/stripe.service.ts +++ b/demo-angular/app/demo/stripe.service.ts @@ -46,7 +46,7 @@ export class StripeService implements StripeBackendAPI { // PaymentIntent createPaymentIntent(amount: number, currency: string = 'usd'): Promise { const content = `amount=${amount}¤cy=${currency}`; - return this._postRequest("create_intent", content).then(response => response.content.toJSON()); + return this._postRequest("create_payment_intent", content).then(response => response.content.toJSON()); } createCustomerKey(apiVersion: string): Promise { @@ -55,14 +55,14 @@ export class StripeService implements StripeBackendAPI { } capturePayment(stripeID: string, amount: number, shippingMethod?: StripeShippingMethod, shippingAddress?: StripeAddress): Promise { - let content = `payment_method=${stripeID}&amount=${amount}`; + let content = `payment_method_id=${stripeID}&amount=${amount}`; if (shippingMethod && shippingAddress) content += `&${this._encodeShipping(shippingMethod, shippingAddress)}`; - return this._postRequest("capture_payment", content).then(response => response.content.toJSON()); + return this._postRequest("confirm_payment_intent", content).then(response => response.content.toJSON()); } confirmPaymentIntent(paymentIntentID: string): Promise { const content = `payment_intent_id=${paymentIntentID}`; - return this._postRequest("confirm_payment", content).then(response => response.content.toJSON()); + return this._postRequest("confirm_payment_intent", content).then(response => response.content.toJSON()); } createPaymentSession(page: Page, price: number, listener?: StripePaymentListener): StripePaymentSession { @@ -94,7 +94,7 @@ export class StripeService implements StripeBackendAPI { content }).then(response => { if (response.statusCode < 200 || response.statusCode >= 300) { - throw new Error(response.content.toString()); + throw new Error(`Status: ${response.statusCode}; ${response.content.toString()}.`); } return response; });