UNPKG

@exodus/react-native-payments

Version:

[![react-native version](https://img.shields.io/badge/react--native-0.41-0ba7d3.svg?style=flat-square)](http://facebook.github.io/react-native/releases/0.40) [![npm](https://img.shields.io/npm/v/react-native-payments.svg?style=flat-square)](https://www.np

201 lines (200 loc) 8.37 kB
import { DeviceEventEmitter, Platform } from 'react-native'; import { randomUUID } from '@exodus/crypto/randomUUID'; import NativePayments from './NativePayments'; import PaymentResponse from './PaymentResponse'; import PaymentRequestUpdateEvent from './PaymentRequestUpdateEvent'; import { ConstructorError } from './errors'; import { convertDetailAmountsToString, getPlatformMethodData, validateTotal, validatePaymentMethods, validateDisplayItems, validateShippingOptions, getSelectedShippingOption, transformMerchantCapabilities } from './helpers'; import { SHIPPING_ADDRESS_CHANGE_EVENT, SHIPPING_OPTION_CHANGE_EVENT, INTERNAL_SHIPPING_ADDRESS_CHANGE_EVENT, INTERNAL_SHIPPING_OPTION_CHANGE_EVENT, USER_DISMISS_EVENT, USER_ACCEPT_EVENT } from './constants'; const noop = () => { }; const IS_ANDROID = Platform.OS === 'android'; const IS_IOS = Platform.OS === 'ios'; export default class PaymentRequest { _id; _shippingAddress; _shippingOption; _shippingType; _acceptPromiseResolver; _acceptPromiseRejecter; _serializedMethodData; _details; _options; _state; _updating; _shippingAddressChangesCount; _shippingAddressChangeFn; _shippingOptionChangeFn; _shippingAddressChangeSubscription; _shippingOptionChangeSubscription; _userDismissSubscription; _userAcceptSubscription; static canMakePaymentsUsingNetworks = NativePayments.canMakePaymentsUsingNetworks; static MerchantCapabilities = { debit: 'debit', credit: 'credit', emv: 'emv' }; constructor(methodData = [], details, options = Object.create(null)) { options = { ...options }; options.merchantCapabilities = transformMerchantCapabilities(options.merchantCapabilities); noop(); if (!details.id) { details.id = randomUUID(); } validatePaymentMethods(methodData); validateTotal(details.total, ConstructorError); validateDisplayItems(details.displayItems, ConstructorError); let selectedShippingOption = null; validateShippingOptions(details, ConstructorError); if (IS_IOS) { selectedShippingOption = getSelectedShippingOption(details.shippingOptions); } noop(); noop(); this._options = options; this._state = 'created'; this._updating = false; this._details = details; this._serializedMethodData = JSON.stringify(methodData); this._id = details.id; this._shippingOption = selectedShippingOption; this._shippingAddress = null; this._shippingType = IS_IOS && options.shippingType && options.requestShipping === true ? options.shippingType : null; this._setupEventListeners(); this._shippingAddressChangesCount = 0; const platformMethodData = getPlatformMethodData(methodData, Platform.OS); const normalizedDetails = convertDetailAmountsToString(details); NativePayments.createPaymentRequest(platformMethodData, normalizedDetails, options); } _setupEventListeners() { this._userDismissSubscription = DeviceEventEmitter.addListener(USER_DISMISS_EVENT, this._closePaymentRequest.bind(this)); this._userAcceptSubscription = DeviceEventEmitter.addListener(USER_ACCEPT_EVENT, this._handleUserAccept.bind(this)); if (IS_IOS) { this._shippingOptionChangeSubscription = DeviceEventEmitter.addListener(INTERNAL_SHIPPING_OPTION_CHANGE_EVENT, this._handleShippingOptionChange.bind(this)); this._shippingAddressChangeSubscription = DeviceEventEmitter.addListener(INTERNAL_SHIPPING_ADDRESS_CHANGE_EVENT, this._handleShippingAddressChange.bind(this)); } } _handleShippingAddressChange(postalAddress) { this._shippingAddress = postalAddress; const event = new PaymentRequestUpdateEvent(SHIPPING_ADDRESS_CHANGE_EVENT, this); this._shippingAddressChangesCount++; if (IS_IOS && this._shippingAddressChangesCount === 1) { return event.updateWith(this._details); } this._shippingAddressChangeFn?.(event); } _handleShippingOptionChange(value) { this._shippingOption = value.selectedShippingOptionId; const event = new PaymentRequestUpdateEvent(SHIPPING_OPTION_CHANGE_EVENT, this); this._shippingOptionChangeFn?.(event); } _getPlatformDetails(details) { const { paymentData: serializedPaymentData, billingContact: serializedBillingContact, shippingContact: serializedShippingContact, paymentToken, transactionIdentifier, paymentMethod } = details; const isSimulator = transactionIdentifier === 'Simulated Identifier'; let billingContact = null; let shippingContact = null; if (serializedBillingContact && serializedBillingContact !== '') { try { billingContact = JSON.parse(serializedBillingContact); } catch (e) { } } if (serializedShippingContact && serializedShippingContact !== '') { try { shippingContact = JSON.parse(serializedShippingContact); } catch (e) { } } return { paymentData: isSimulator ? null : JSON.parse(serializedPaymentData), billingContact, shippingContact, paymentToken, transactionIdentifier, paymentMethod }; } _handleUserAccept(details) { if (IS_ANDROID) { const { shippingAddress } = details; this._shippingAddress = shippingAddress; } const paymentResponse = new PaymentResponse({ requestId: this.id, methodName: IS_IOS ? 'apple-pay' : 'android-pay', shippingAddress: this._options.requestShipping ? this._shippingAddress : null, details: this._getPlatformDetails(details), shippingOption: IS_IOS ? this._shippingOption ?? null : null, payerName: this._options.requestPayerName ? this._shippingAddress?.recipient ?? null : null, payerPhone: this._options.requestPayerPhone ? this._shippingAddress?.phone ?? null : null, payerEmail: IS_ANDROID && this._options.requestPayerEmail ? details.payerEmail : null }); return this._acceptPromiseResolver?.(paymentResponse); } _closePaymentRequest(reject = true) { this._state = 'closed'; if (reject) this._acceptPromiseRejecter?.(new Error('AbortError')); this._removeEventListeners(); } _removeEventListeners() { this._userDismissSubscription?.remove(); this._userAcceptSubscription?.remove(); if (IS_IOS) { this._shippingAddressChangeSubscription?.remove(); this._shippingOptionChangeSubscription?.remove(); } } stopRequest() { if (this._state !== 'closed') this._closePaymentRequest(false); } addEventListener(eventName, fn) { if (eventName === SHIPPING_ADDRESS_CHANGE_EVENT) { return (this._shippingAddressChangeFn = fn.bind(this)); } if (eventName === SHIPPING_OPTION_CHANGE_EVENT) { return (this._shippingOptionChangeFn = fn.bind(this)); } } get id() { return this._id; } get shippingAddress() { return this._shippingAddress; } get shippingOption() { return this._shippingOption; } show() { return new Promise((resolve, reject) => { this._acceptPromiseResolver = resolve; this._acceptPromiseRejecter = reject; if (this._state !== 'created') { return reject(new Error('InvalidStateError')); } this._state = 'interactive'; NativePayments.show().catch(reject); }); } async abort() { if (this._state !== 'interactive') { throw new Error('InvalidStateError'); } try { await NativePayments.abort(); this._closePaymentRequest(); } catch (error) { throw new Error('InvalidStateError'); } } canMakePayments() { return NativePayments.canMakePayments(); } }