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

162 lines (161 loc) 6.53 kB
import { DOMException, ConstructorError } from '../errors'; function isNumber(value) { return typeof value === 'number'; } function isString(value) { return typeof value === 'string'; } const CAPABILITIES = new Set(['emv', 'debit', 'credit']); export function transformMerchantCapabilities(merchantCapabilities) { if (!merchantCapabilities) return undefined; if (Array.isArray(merchantCapabilities)) { merchantCapabilities = merchantCapabilities.reduce((acc, capability) => { acc[capability] = true; return acc; }, Object.create(null)); } for (const key in merchantCapabilities) { if (!CAPABILITIES.has(key)) { throw new TypeError(`Invalid merchant capability: ${key}`); } } return merchantCapabilities; } export function isValidDecimalMonetaryValue(amountValue) { if (!isNumber(amountValue) && !isString(amountValue)) { return false; } return isNumber(amountValue) || isValidStringAmount(amountValue); } export function isNegative(amountValue) { return isNumber(amountValue) ? amountValue < 0 : amountValue.startsWith('-'); } export function isValidStringAmount(stringAmount) { if (typeof stringAmount !== 'string') throw new TypeError('Expected a string'); return /^[-+]?(?:\.[0-9]+|[0-9]+(?:\.[0-9]+)?)$/.test(stringAmount); } export function toString(amountValue) { return isNumber(amountValue) ? amountValue.toString() : amountValue; } export function convertObjectAmountToString(objectWithAmount) { return Object.assign(Object.create(null), objectWithAmount, { amount: Object.assign(Object.create(null), { value: toString(objectWithAmount.amount.value), currency: objectWithAmount.amount.currency }) }); } export function convertDetailAmountsToString(details) { const nextDetails = Object.keys(details).reduce((acc, key) => { if (key === 'total') { return Object.assign(Object.create(null), acc, { [key]: convertObjectAmountToString(details[key]) }); } if (Array.isArray(details[key]) && (key === 'displayItems' || key === 'shippingOptions')) { return Object.assign(Object.create(null), acc, { [key]: details[key].map(paymentItemOrShippingOption => convertObjectAmountToString(paymentItemOrShippingOption)) }); } return acc; }, Object.create(null)); return nextDetails; } export function getPlatformMethodData(methodData, platformOS) { const platformSupportedMethod = platformOS === 'ios' ? 'apple-pay' : 'android-pay'; const platformMethod = methodData.find(paymentMethodData => paymentMethodData.supportedMethods.includes(platformSupportedMethod)); if (!platformMethod) { throw new DOMException('NotSupportedError'); } return platformMethod.data; } export function validateTotal(total, errorType = Error) { if (total === undefined) { throw new errorType(`required member total is undefined.`); } const hasTotal = total && total.amount && total.amount.value; if (!hasTotal) { throw new errorType(`Missing required member(s): amount, label.`); } const totalAmountValue = total.amount.value; if (!isValidDecimalMonetaryValue(totalAmountValue)) { throw new errorType(`'${totalAmountValue}' is not a valid amount format for total`); } if (isNegative(totalAmountValue)) { throw new errorType(`Total amount value should be non-negative`); } } export function validatePaymentMethods(methodData) { if (methodData.length < 1) { throw new ConstructorError(`At least one payment method is required`); } methodData.forEach(paymentMethod => { if (paymentMethod.supportedMethods === undefined) { throw new ConstructorError(`required member supportedMethods is undefined.`); } if (!Array.isArray(paymentMethod.supportedMethods)) { throw new ConstructorError(`required member supportedMethods is not iterable.`); } if (paymentMethod.supportedMethods.length < 1) { throw new ConstructorError(`Each payment method needs to include at least one payment method identifier`); } }); } export function validateDisplayItems(displayItems, errorType = Error) { if (displayItems) { displayItems.forEach((item) => { const amountValue = item && item.amount && item.amount.value; if (!amountValue) { throw new errorType(`required member value is undefined.`); } if (!isValidDecimalMonetaryValue(amountValue)) { throw new errorType(`'${amountValue}' is not a valid amount format for display items`); } }); } } export function validateShippingOptions(details, errorType = Error) { if (details.shippingOptions === undefined) { return undefined; } if (!Array.isArray(details.shippingOptions)) { throw new errorType(`Iterator getter is not callable.`); } if (details.shippingOptions) { let seenIDs = []; details.shippingOptions.forEach((shippingOption) => { if (shippingOption.id === undefined) { throw new errorType(`required member id is undefined.`); } if (shippingOption.id === null) { shippingOption.id = 'null'; } const amountValue = shippingOption.amount.value; if (!isValidDecimalMonetaryValue(amountValue)) { throw new errorType(`'${amountValue}' is not a valid amount format for shippingOptions`); } if (seenIDs.includes(shippingOption.id)) { details.shippingOptions = []; console.warn(`[ReactNativePayments] Duplicate shipping option identifier '${shippingOption.id}' is treated as an invalid address indicator.`); return undefined; } seenIDs.push(shippingOption.id); }); } } export function getSelectedShippingOption(shippingOptions) { if (!Array.isArray(shippingOptions)) { return null; } if (shippingOptions.length === 0) { return null; } const selectedShippingOption = shippingOptions.find(shippingOption => shippingOption.selected); if (selectedShippingOption) { return selectedShippingOption.id; } return shippingOptions[0]?.id ?? null; }