diff --git a/android/src/main/java/com/stripeterminalreactnative/Mappers.kt b/android/src/main/java/com/stripeterminalreactnative/Mappers.kt index 99a40648..71a88865 100644 --- a/android/src/main/java/com/stripeterminalreactnative/Mappers.kt +++ b/android/src/main/java/com/stripeterminalreactnative/Mappers.kt @@ -499,8 +499,8 @@ internal fun mapFromNetworkStatus(status: NetworkStatus): String { } } -fun mapFromOfflineStatus(offlineStatus: OfflineStatus): ReadableMap = - nativeMapOf { +fun mapFromOfflineStatus(offlineStatus: OfflineStatus): ReadableMap { + val sdkMap = nativeMapOf { putString("networkStatus", mapFromNetworkStatus(offlineStatus.sdk.networkStatus)) putInt("offlinePaymentsCount", offlineStatus.sdk.offlinePaymentsCount) @@ -512,3 +512,23 @@ fun mapFromOfflineStatus(offlineStatus: OfflineStatus): ReadableMap = putMap("offlinePaymentAmountsByCurrency", map) } + val readerMap = nativeMapOf { + offlineStatus.reader?.also { reader -> + putString("networkStatus", mapFromNetworkStatus(reader.networkStatus)) + putInt("offlinePaymentsCount", reader.offlinePaymentsCount) + + val map = nativeMapOf { + reader.offlinePaymentAmountsByCurrency.forEach { + putInt(it.key, it.value.toInt()) + } + } + putMap("offlinePaymentAmountsByCurrency", map) + } + + } + + return nativeMapOf { + putMap("sdk", sdkMap) + putMap("reader", readerMap) + } +} diff --git a/android/src/main/java/com/stripeterminalreactnative/StripeTerminalReactNativeModule.kt b/android/src/main/java/com/stripeterminalreactnative/StripeTerminalReactNativeModule.kt index f1bd6b2e..cf4c8e4a 100644 --- a/android/src/main/java/com/stripeterminalreactnative/StripeTerminalReactNativeModule.kt +++ b/android/src/main/java/com/stripeterminalreactnative/StripeTerminalReactNativeModule.kt @@ -696,34 +696,7 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) : @ReactMethod @Suppress("unused") fun getOfflineStatus(promise: Promise) { - promise.resolve( - nativeMapOf { - val sdkMap = nativeMapOf { - putInt("offlinePaymentsCount", terminal.offlineStatus.sdk.offlinePaymentsCount) - - val map = nativeMapOf { - terminal.offlineStatus.sdk.offlinePaymentAmountsByCurrency.forEach { - putInt(it.key, it.value.toInt()) - } - } - putMap("offlinePaymentAmountsByCurrency", map) - } - - val readerMap = nativeMapOf { - putInt("offlinePaymentsCount", terminal.offlineStatus.reader?.offlinePaymentsCount?:0) - - val map = nativeMapOf { - terminal.offlineStatus.reader?.offlinePaymentAmountsByCurrency?.forEach { - putInt(it.key, it.value.toInt()) - } - } - putMap("offlinePaymentAmountsByCurrency", map) - } - - putMap("sdk", sdkMap) - putMap("reader", readerMap) - } - ) + promise.resolve(mapFromOfflineStatus(terminal.offlineStatus)) } private fun cancelOperation( diff --git a/android/src/main/java/com/stripeterminalreactnative/listener/RNOfflineListener.kt b/android/src/main/java/com/stripeterminalreactnative/listener/RNOfflineListener.kt index 4e52fbca..07f15191 100644 --- a/android/src/main/java/com/stripeterminalreactnative/listener/RNOfflineListener.kt +++ b/android/src/main/java/com/stripeterminalreactnative/listener/RNOfflineListener.kt @@ -26,10 +26,12 @@ class RNOfflineListener( override fun onPaymentIntentForwarded(paymentIntent: PaymentIntent, e: TerminalException?) { context.sendEvent(ReactNativeConstants.FORWARD_PAYMENT_INTENT.listenerName) { putMap("result", mapFromPaymentIntent(paymentIntent, "")) - putMap("error", nativeMapOf { - putString("code", e?.errorCode.toString()) - putString("message", e?.errorMessage) - }) + if (e != null) { + putMap("error", nativeMapOf { + putString("code", e.errorCode.toString()) + putString("message", e.errorMessage) + }) + } } } diff --git a/dev-app/src/screens/DatabaseScreen.tsx b/dev-app/src/screens/DatabaseScreen.tsx index 686e60af..b11f0a5f 100644 --- a/dev-app/src/screens/DatabaseScreen.tsx +++ b/dev-app/src/screens/DatabaseScreen.tsx @@ -1,6 +1,6 @@ import React, { useContext, useEffect, useState } from 'react'; import { ScrollView, StyleSheet, Text } from 'react-native'; -import type { OfflinePaymentStatus } from 'src/types'; +import type { OfflineStatus } from 'src/types'; import { colors } from '../colors'; import List from '../components/List'; import ListItem from '../components/ListItem'; @@ -10,7 +10,7 @@ import { useStripeTerminal } from '@stripe/stripe-terminal-react-native'; export default function DatabaseScreen() { const { account } = useContext(AppContext); const [offlinePaymentStatus, setOfflinePaymentStatus] = - useState(null); + useState(null); const currencySymbols = [ { value: 'usd', label: '$' }, { value: 'gbp', label: '£' }, diff --git a/dev-app/src/screens/HomeScreen.tsx b/dev-app/src/screens/HomeScreen.tsx index 0255a3df..415ffeba 100644 --- a/dev-app/src/screens/HomeScreen.tsx +++ b/dev-app/src/screens/HomeScreen.tsx @@ -33,8 +33,8 @@ export default function HomeScreen() { useState('bluetoothScan'); const { disconnectReader, connectedReader } = useStripeTerminal({ onDidChangeOfflineStatus(status: OfflineStatus) { - console.log('offline status = ' + status.networkStatus); - setOnline(status.networkStatus == 'online' ? true : false); + console.log(status); + setOnline(status.sdk.networkStatus === 'online' ? true : false); }, onDidForwardingFailure(error) { console.log('onDidForwardingFailure ' + error?.message); @@ -56,9 +56,9 @@ export default function HomeScreen() { 'Payment Intent ' + paymentIntent.id + ' forwarded. ErrorCode' + - error.code + + error?.code + '. ErrorMsg = ' + - error.message; + error?.message; let toast = Toast.show(toastMsg, { duration: Toast.durations.LONG, position: Toast.positions.BOTTOM, diff --git a/ios/Errors.swift b/ios/Errors.swift index b46d7566..169a881a 100644 --- a/ios/Errors.swift +++ b/ios/Errors.swift @@ -26,7 +26,7 @@ class Errors { return createError(errorCode: code.rawValue, message: message) } - class func createError(nsError: NSError) -> [String: Any?] { + class func createError(nsError: NSError) -> [String: Any] { return createError(code: ErrorCode.Code.init(rawValue: nsError.code) ?? ErrorCode.unexpectedSdkError, message: nsError.localizedDescription) } diff --git a/ios/Mappers.swift b/ios/Mappers.swift index cd4a3793..7e049f22 100644 --- a/ios/Mappers.swift +++ b/ios/Mappers.swift @@ -518,10 +518,22 @@ class Mappers { } class func mapFromOfflineStatus(_ offlineStatus: OfflineStatus) -> NSDictionary { - let result: NSDictionary = [ - "networkStatus": mapFromNetworkStatus(offlineStatus.sdk.networkStatus) - ] - return result + let sdkDict: NSDictionary = [ + "networkStatus": Mappers.mapFromNetworkStatus(offlineStatus.sdk.networkStatus), + "offlinePaymentsCount": offlineStatus.sdk.paymentsCount ?? 0, + "offlinePaymentAmountsByCurrency": offlineStatus.sdk.paymentAmountsByCurrency + ] + + var readerDict: NSDictionary = [:] + if let reader = offlineStatus.reader { + readerDict = [ + "networkStatus": Mappers.mapFromNetworkStatus(reader.networkStatus), + "offlinePaymentsCount": reader.paymentsCount ?? 0, + "offlinePaymentAmountsByCurrency": reader.paymentAmountsByCurrency + ] + } + + return(["sdk": sdkDict, "reader": readerDict]) } } diff --git a/ios/StripeTerminalReactNative.swift b/ios/StripeTerminalReactNative.swift index b92970cd..3c2ac28e 100644 --- a/ios/StripeTerminalReactNative.swift +++ b/ios/StripeTerminalReactNative.swift @@ -915,17 +915,9 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe @objc(getOfflineStatus:rejecter:) func getOfflineStatus(resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) { - let sdkDic: NSDictionary = [ - "offlinePaymentsCount": Terminal.shared.offlineStatus.sdk.paymentsCount ?? 0, - "offlinePaymentAmountsByCurrency": Terminal.shared.offlineStatus.sdk.paymentAmountsByCurrency - ] - - let readDic: NSDictionary = [ - "offlinePaymentsCount": Terminal.shared.offlineStatus.reader?.paymentsCount ?? 0, - "offlinePaymentAmountsByCurrency": Terminal.shared.offlineStatus.reader?.paymentAmountsByCurrency ?? {} - ] + let result = Mappers.mapFromOfflineStatus(Terminal.shared.offlineStatus) - resolve(["sdk": sdkDic, "reader": readDic]) + resolve(result) } func reader(_ reader: Reader, didReportAvailableUpdate update: ReaderSoftwareUpdate) { @@ -1003,13 +995,24 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe } func terminal(_ terminal: Terminal, didChange offlineStatus: OfflineStatus) { - let offlineStatus = Mappers.mapFromOfflineStatus(offlineStatus) - sendEvent(withName: ReactNativeConstants.CHANGE_OFFLINE_STATUS.rawValue, body: ["result": offlineStatus]) + let result = Mappers.mapFromOfflineStatus(offlineStatus) + sendEvent(withName: ReactNativeConstants.CHANGE_OFFLINE_STATUS.rawValue, body: ["result": result]) } func terminal(_ terminal: Terminal, didForwardPaymentIntent intent: PaymentIntent, error: Error?) { let result = Mappers.mapFromPaymentIntent(intent, uuid: "") - sendEvent(withName: ReactNativeConstants.FORWARD_PAYMENT_INTENT.rawValue, body: ["result": result]) + var body: [String: Any] = ["result": result] + + if let nsError = error as NSError? { + let errorAsDictionary = Errors.createError(nsError: nsError) + // createError will return a dictionary of ["error": {the error}] + // so merge that with the result so we have [result:, error:] + body = body.merging(errorAsDictionary, uniquingKeysWith: { _, error in + error + }) + } + + sendEvent(withName: ReactNativeConstants.FORWARD_PAYMENT_INTENT.rawValue, body: body) } func terminal(_ terminal: Terminal, didReportForwardingError error: Error) { diff --git a/src/StripeTerminalSdk.tsx b/src/StripeTerminalSdk.tsx index 5de1280c..e0d98c77 100644 --- a/src/StripeTerminalSdk.tsx +++ b/src/StripeTerminalSdk.tsx @@ -29,7 +29,7 @@ import type { CollectPaymentMethodParams, PaymentIntent, SetupIntent, - OfflinePaymentStatus, + OfflineStatus, } from './types'; const { StripeTerminalReactNative } = NativeModules; @@ -139,7 +139,7 @@ export interface StripeTerminalSdkType { setSimulatedCard(cardNumber: string): Promise<{ error?: StripeError; }>; - getOfflineStatus(): Promise; + getOfflineStatus(): Promise; } export default StripeTerminalReactNative as StripeTerminalSdkType; diff --git a/src/components/StripeTerminalProvider.tsx b/src/components/StripeTerminalProvider.tsx index 71db1c6a..7250bffd 100644 --- a/src/components/StripeTerminalProvider.tsx +++ b/src/components/StripeTerminalProvider.tsx @@ -210,7 +210,7 @@ export function StripeTerminalProvider({ const didChangeOfflineStatus = useCallback( ({ result }: { result?: OfflineStatus }) => { - log('didChangeOfflineStatus'); + log('didChangeOfflineStatus', result); emitter?.emit(CHANGE_OFFLINE_STATUS, result); }, [log] @@ -218,7 +218,7 @@ export function StripeTerminalProvider({ const didForwardPaymentIntent = useCallback( ({ result, error }: { result: PaymentIntent.Type; error: StripeError }) => { - log('didForwardPaymentIntent'); + log('didForwardPaymentIntent', { ...result, ...error }); emitter?.emit(FORWARD_PAYMENT_INTENT, result, error); }, [log] @@ -226,7 +226,7 @@ export function StripeTerminalProvider({ const didReportForwardingError = useCallback( ({ error }: { error?: StripeError }) => { - log('didReportForwardingError'); + log('didReportForwardingError', error); emitter?.emit(REPORT_FORWARDING_ERROR, error); }, [log] diff --git a/src/functions.ts b/src/functions.ts index a26b8bd9..2062adcc 100644 --- a/src/functions.ts +++ b/src/functions.ts @@ -30,7 +30,7 @@ import type { CollectPaymentMethodParams, PaymentIntent, SetupIntent, - OfflinePaymentStatus, + OfflineStatus, } from './types'; export async function initialize( @@ -742,7 +742,7 @@ export async function cancelCollectSetupIntent(): Promise<{ }, 'cancelCollectSetupIntent')(); } -export async function getOfflineStatus(): Promise { +export async function getOfflineStatus(): Promise { return Logger.traceSdkMethod(async () => { try { const offlineStatus = await StripeTerminalSdk.getOfflineStatus(); diff --git a/src/hooks/useStripeTerminal.tsx b/src/hooks/useStripeTerminal.tsx index 5d761488..8043fa92 100644 --- a/src/hooks/useStripeTerminal.tsx +++ b/src/hooks/useStripeTerminal.tsx @@ -275,6 +275,9 @@ export function useStripeTerminal(props?: Props) { const didChangeOfflineStatus = useCallback( ({ result }: { result: OfflineStatus }) => { + if (!result.reader?.networkStatus) { + result.reader = undefined; + } onDidChangeOfflineStatus?.(result); }, [onDidChangeOfflineStatus] @@ -835,6 +838,9 @@ export function useStripeTerminal(props?: Props) { throw Error(NOT_INITIALIZED_ERROR_MESSAGE); } const response = await getOfflineStatus(); + if (response.reader?.networkStatus) { + response.reader = undefined; + } return response; }, [_isInitialized]); diff --git a/src/types/index.ts b/src/types/index.ts index 4de5c295..2f5f15e1 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -272,21 +272,15 @@ export type ConfirmRefundResultType = { error?: StripeError; }; -export type OfflineStatus = { +export type OfflineStatusDetails = { networkStatus: 'online' | 'offline' | 'unknown'; offlinePaymentsCount: number; offlinePaymentAmountsByCurrency: { [key: string]: number }; }; -export type OfflinePaymentStatus = { - sdk: { - offlinePaymentsCount: number; - offlinePaymentAmountsByCurrency: { [key: string]: number }; - }; - reader: { - offlinePaymentsCount: number; - offlinePaymentAmountsByCurrency: { [key: string]: number }; - }; +export type OfflineStatus = { + sdk: OfflineStatusDetails; + reader?: OfflineStatusDetails; }; type CardDetails = {