From 40846346e1a63fb6b55ee150b741dfe8e150e8f7 Mon Sep 17 00:00:00 2001 From: eric lin <128665795+EricLin-BBpos@users.noreply.github.com> Date: Thu, 30 May 2024 05:27:47 +0800 Subject: [PATCH] Add missing Reader callbacks (#706) * Add missing Reader callbacks * fix missing import * add __snapshots__ file * rename paramter * add callback in UsbReaderListener * rename parameter * code optimization * change parameter type * remove unuse code * update * rename swift parameter --------- Co-authored-by: Nazli Yurdakul <69359432+nazli-stripe@users.noreply.github.com> --- .../com/stripeterminalreactnative/Mappers.kt | 11 ++++++ .../ReactNativeConstants.kt | 5 ++- .../listener/RNBluetoothReaderListener.kt | 37 +++++++++++++++++++ .../listener/RNUsbReaderListener.kt | 37 +++++++++++++++++++ ios/Mappers.swift | 8 ++++ ios/StripeTerminalReactNative.swift | 22 +++++++++++ src/components/StripeTerminalProvider.tsx | 32 ++++++++++++++++ src/hooks/useStripeTerminal.tsx | 29 +++++++++++++++ src/types/Reader.ts | 6 +++ src/types/index.ts | 6 +++ 10 files changed, 192 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/stripeterminalreactnative/Mappers.kt b/android/src/main/java/com/stripeterminalreactnative/Mappers.kt index ac4f8ef1..7b555abd 100644 --- a/android/src/main/java/com/stripeterminalreactnative/Mappers.kt +++ b/android/src/main/java/com/stripeterminalreactnative/Mappers.kt @@ -9,6 +9,7 @@ import com.stripe.stripeterminal.external.CollectInputs import com.stripe.stripeterminal.external.OfflineMode import com.stripe.stripeterminal.external.models.Address import com.stripe.stripeterminal.external.models.AmountDetails +import com.stripe.stripeterminal.external.models.BatteryStatus import com.stripe.stripeterminal.external.models.CardDetails import com.stripe.stripeterminal.external.models.CardPresentDetails import com.stripe.stripeterminal.external.models.CartLineItem @@ -834,3 +835,13 @@ fun mapFromReaderSupportResult(readerSupportResult: ReaderSupportResult): Readab putBoolean("readerSupportResult", readerSupportResult.isSupported) } } + +fun mapFromBatteryStatus(status: BatteryStatus): String { + return when (status) { + BatteryStatus.CRITICAL -> "CRITICAL" + BatteryStatus.LOW -> "LOW" + BatteryStatus.NOMINAL -> "NOMINAL" + BatteryStatus.UNKNOWN -> "UNKNOWN" + else -> { "UNKNOWN" } + } +} diff --git a/android/src/main/java/com/stripeterminalreactnative/ReactNativeConstants.kt b/android/src/main/java/com/stripeterminalreactnative/ReactNativeConstants.kt index d2faea38..4fd7fe6d 100644 --- a/android/src/main/java/com/stripeterminalreactnative/ReactNativeConstants.kt +++ b/android/src/main/java/com/stripeterminalreactnative/ReactNativeConstants.kt @@ -19,5 +19,8 @@ enum class ReactNativeConstants(val listenerName: String) { CHANGE_OFFLINE_STATUS("didChangeOfflineStatus"), FORWARD_PAYMENT_INTENT("didForwardPaymentIntent"), REPORT_FORWARDING_ERROR("didReportForwardingError"), - DISCONNECT("didDisconnect") + DISCONNECT("didDisconnect"), + UPDATE_BATTERY_LEVEL("didUpdateBatteryLevel"), + REPORT_LOW_BATTERY_WARNING("didReportLowBatteryWarning"), + REPORT_READER_EVENT("didReportReaderEvent"), } diff --git a/android/src/main/java/com/stripeterminalreactnative/listener/RNBluetoothReaderListener.kt b/android/src/main/java/com/stripeterminalreactnative/listener/RNBluetoothReaderListener.kt index 6422aeb6..0f6cb844 100644 --- a/android/src/main/java/com/stripeterminalreactnative/listener/RNBluetoothReaderListener.kt +++ b/android/src/main/java/com/stripeterminalreactnative/listener/RNBluetoothReaderListener.kt @@ -3,7 +3,9 @@ package com.stripeterminalreactnative.listener import com.facebook.react.bridge.ReactApplicationContext import com.stripe.stripeterminal.external.callable.Cancelable import com.stripe.stripeterminal.external.callable.ReaderListener +import com.stripe.stripeterminal.external.models.BatteryStatus import com.stripe.stripeterminal.external.models.DisconnectReason +import com.stripe.stripeterminal.external.models.ReaderEvent import com.stripe.stripeterminal.external.models.ReaderDisplayMessage import com.stripe.stripeterminal.external.models.ReaderInputOptions import com.stripe.stripeterminal.external.models.ReaderSoftwareUpdate @@ -17,11 +19,17 @@ import com.stripeterminalreactnative.ReactNativeConstants.REQUEST_READER_DISPLAY import com.stripeterminalreactnative.ReactNativeConstants.REQUEST_READER_INPUT import com.stripeterminalreactnative.ReactNativeConstants.START_INSTALLING_UPDATE import com.stripeterminalreactnative.mapFromReaderDisconnectReason +import com.stripeterminalreactnative.ReactNativeConstants.UPDATE_BATTERY_LEVEL +import com.stripeterminalreactnative.ReactNativeConstants.REPORT_LOW_BATTERY_WARNING +import com.stripeterminalreactnative.ReactNativeConstants.REPORT_READER_EVENT +import com.stripeterminalreactnative.mapFromBatteryStatus import com.stripeterminalreactnative.mapFromReaderDisplayMessage +import com.stripeterminalreactnative.mapFromReaderEvent import com.stripeterminalreactnative.mapFromReaderInputOptions import com.stripeterminalreactnative.mapFromReaderSoftwareUpdate import com.stripeterminalreactnative.nativeMapOf import com.stripeterminalreactnative.putError +import com.stripeterminalreactnative.putDoubleOrNull class RNBluetoothReaderListener( private val context: ReactApplicationContext, @@ -84,4 +92,33 @@ class RNBluetoothReaderListener( putString("reason", mapFromReaderDisconnectReason(reason)) } } + + override fun onBatteryLevelUpdate( + batteryLevel: Float, + batteryStatus: BatteryStatus, + isCharging: Boolean + ) { + context.sendEvent(UPDATE_BATTERY_LEVEL.listenerName) { + putMap( + "result", + nativeMapOf { + putDoubleOrNull(this,"batteryLevel", batteryLevel.toDouble()) + putString("batteryStatus", mapFromBatteryStatus(batteryStatus)) + putBoolean("isCharging", isCharging) + } + ) + } + } + + override fun onReportLowBatteryWarning() { + context.sendEvent(REPORT_LOW_BATTERY_WARNING.listenerName) { + putString("result", "LOW BATTERY") + } + } + + override fun onReportReaderEvent(event: ReaderEvent) { + context.sendEvent(REPORT_READER_EVENT.listenerName) { + putString("result", mapFromReaderEvent(event)) + } + } } diff --git a/android/src/main/java/com/stripeterminalreactnative/listener/RNUsbReaderListener.kt b/android/src/main/java/com/stripeterminalreactnative/listener/RNUsbReaderListener.kt index 37d070ea..65955fbd 100644 --- a/android/src/main/java/com/stripeterminalreactnative/listener/RNUsbReaderListener.kt +++ b/android/src/main/java/com/stripeterminalreactnative/listener/RNUsbReaderListener.kt @@ -3,7 +3,9 @@ package com.stripeterminalreactnative.listener import com.facebook.react.bridge.ReactApplicationContext import com.stripe.stripeterminal.external.callable.Cancelable import com.stripe.stripeterminal.external.callable.ReaderListener +import com.stripe.stripeterminal.external.models.BatteryStatus import com.stripe.stripeterminal.external.models.DisconnectReason +import com.stripe.stripeterminal.external.models.ReaderEvent import com.stripe.stripeterminal.external.models.ReaderDisplayMessage import com.stripe.stripeterminal.external.models.ReaderInputOptions import com.stripe.stripeterminal.external.models.ReaderSoftwareUpdate @@ -16,12 +18,18 @@ import com.stripeterminalreactnative.ReactNativeConstants.REPORT_UPDATE_PROGRESS import com.stripeterminalreactnative.ReactNativeConstants.REQUEST_READER_DISPLAY_MESSAGE import com.stripeterminalreactnative.ReactNativeConstants.REQUEST_READER_INPUT import com.stripeterminalreactnative.ReactNativeConstants.START_INSTALLING_UPDATE +import com.stripeterminalreactnative.ReactNativeConstants.UPDATE_BATTERY_LEVEL +import com.stripeterminalreactnative.ReactNativeConstants.REPORT_LOW_BATTERY_WARNING +import com.stripeterminalreactnative.ReactNativeConstants.REPORT_READER_EVENT +import com.stripeterminalreactnative.mapFromBatteryStatus import com.stripeterminalreactnative.mapFromReaderDisconnectReason import com.stripeterminalreactnative.mapFromReaderDisplayMessage +import com.stripeterminalreactnative.mapFromReaderEvent import com.stripeterminalreactnative.mapFromReaderInputOptions import com.stripeterminalreactnative.mapFromReaderSoftwareUpdate import com.stripeterminalreactnative.nativeMapOf import com.stripeterminalreactnative.putError +import com.stripeterminalreactnative.putDoubleOrNull class RNUsbReaderListener( private val context: ReactApplicationContext, @@ -84,4 +92,33 @@ class RNUsbReaderListener( putString("reason", mapFromReaderDisconnectReason(reason)) } } + + override fun onBatteryLevelUpdate( + batteryLevel: Float, + batteryStatus: BatteryStatus, + isCharging: Boolean + ) { + context.sendEvent(UPDATE_BATTERY_LEVEL.listenerName) { + putMap( + "result", + nativeMapOf { + putDoubleOrNull(this,"batteryLevel", batteryLevel.toDouble()) + putString("batteryStatus", mapFromBatteryStatus(batteryStatus)) + putBoolean("isCharging", isCharging) + } + ) + } + } + + override fun onReportLowBatteryWarning() { + context.sendEvent(REPORT_LOW_BATTERY_WARNING.listenerName) { + putString("result", "LOW BATTERY") + } + } + + override fun onReportReaderEvent(event: ReaderEvent) { + context.sendEvent(REPORT_READER_EVENT.listenerName) { + putString("result", mapFromReaderEvent(event)) + } + } } diff --git a/ios/Mappers.swift b/ios/Mappers.swift index adf31c3b..586922be 100644 --- a/ios/Mappers.swift +++ b/ios/Mappers.swift @@ -833,6 +833,14 @@ class Mappers { return (["collectInputResults": collectInputResults]) } + + class func mapFromReaderEvent(_ readerEvent: ReaderEvent) -> String { + switch readerEvent { + case .cardInserted: return "cardInserted" + case .cardRemoved: return "cardRemoved" + @unknown default: return "unknown" + } + } } extension UInt { diff --git a/ios/StripeTerminalReactNative.swift b/ios/StripeTerminalReactNative.swift index 388c7014..1664699e 100644 --- a/ios/StripeTerminalReactNative.swift +++ b/ios/StripeTerminalReactNative.swift @@ -21,6 +21,9 @@ enum ReactNativeConstants: String, CaseIterable { case FORWARD_PAYMENT_INTENT = "didForwardPaymentIntent" case REPORT_FORWARDING_ERROR = "didReportForwardingError" case DISCONNECT = "didDisconnect" + case UPDATE_BATTERY_LEVEL = "didUpdateBatteryLevel" + case REPORT_LOW_BATTERY_WARNING = "didReportLowBatteryWarning" + case REPORT_READER_EVENT = "didReportReaderEvent" } @objc(StripeTerminalReactNative) @@ -1405,4 +1408,23 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe let result = Errors.createError(nsError: error as NSError) sendEvent(withName: ReactNativeConstants.REPORT_FORWARDING_ERROR.rawValue, body: ["result": result]) } + + func reader(_ reader: Reader, didReportReaderEvent event: ReaderEvent, info: [AnyHashable : Any]?) { + let result = Mappers.mapFromReaderEvent(event) + sendEvent(withName: ReactNativeConstants.REPORT_READER_EVENT.rawValue, body: ["result": result]) + } + + func reader(_ reader: Reader, didReportBatteryLevel batteryLevel: Float, status: BatteryStatus, isCharging: Bool) { + let result: NSDictionary = [ + "batteryLevel": batteryLevel, + "batteryStatus": Mappers.mapFromBatteryStatus(status), + "isCharging": isCharging, + ] + sendEvent(withName: ReactNativeConstants.UPDATE_BATTERY_LEVEL.rawValue, body: ["result": result]) + } + + func readerDidReportLowBatteryWarning(_ reader: Reader) { + let result = "LOW BATTERY" + sendEvent(withName: ReactNativeConstants.REPORT_LOW_BATTERY_WARNING.rawValue, body: ["result": result]) + } } diff --git a/src/components/StripeTerminalProvider.tsx b/src/components/StripeTerminalProvider.tsx index cfcb1ac0..8d6153b0 100644 --- a/src/components/StripeTerminalProvider.tsx +++ b/src/components/StripeTerminalProvider.tsx @@ -8,6 +8,7 @@ import { PaymentStatus, OfflineStatus, PaymentIntent, + ReaderEvent, } from '../types'; import { StripeTerminalContext } from './StripeTerminalContext'; import { initialize, setConnectionToken } from '../functions'; @@ -35,6 +36,9 @@ const { FORWARD_PAYMENT_INTENT, REPORT_FORWARDING_ERROR, DISCONNECT, + UPDATE_BATTERY_LEVEL, + REPORT_LOW_BATTERY_WARNING, + REPORT_READER_EVENT, } = NativeModules.StripeTerminalReactNative.getConstants(); const emitter = new EventEmitter(); @@ -241,6 +245,30 @@ export function StripeTerminalProvider({ [log] ); + const didUpdateBatteryLevel = useCallback( + ({ result }: { result?: Reader.BatteryLevel }) => { + log('didUpdateBatteryLevel', result); + emitter?.emit(UPDATE_BATTERY_LEVEL, result); + }, + [log] + ); + + const didReportLowBatteryWarning = useCallback( + ({ result }: { result?: string }) => { + log('didReportLowBatteryWarning', result); + emitter?.emit(REPORT_LOW_BATTERY_WARNING, result); + }, + [log] + ); + + const didReportReaderEvent = useCallback( + ({ result }: EventResult) => { + log('didReportReaderEvent', result); + emitter?.emit(REPORT_READER_EVENT, result); + }, + [log] + ); + useListener(REPORT_AVAILABLE_UPDATE, didReportAvailableUpdate); useListener(START_INSTALLING_UPDATE, didStartInstallingUpdate); useListener(REPORT_UPDATE_PROGRESS, didReportReaderSoftwareUpdateProgress); @@ -267,6 +295,10 @@ export function StripeTerminalProvider({ useListener(DISCONNECT, didDisconnect); + useListener(UPDATE_BATTERY_LEVEL, didUpdateBatteryLevel); + useListener(REPORT_LOW_BATTERY_WARNING, didReportLowBatteryWarning); + useListener(REPORT_READER_EVENT, didReportReaderEvent); + const tokenProviderHandler = async () => { try { const connectionToken = await tokenProvider(); diff --git a/src/hooks/useStripeTerminal.tsx b/src/hooks/useStripeTerminal.tsx index 52ab7057..df73b754 100644 --- a/src/hooks/useStripeTerminal.tsx +++ b/src/hooks/useStripeTerminal.tsx @@ -22,6 +22,7 @@ import type { SetupIntent, OfflineStatus, CollectInputsParameters, + ReaderEvent, } from '../types'; import { discoverReaders, @@ -93,6 +94,9 @@ export const { FORWARD_PAYMENT_INTENT, REPORT_FORWARDING_ERROR, DISCONNECT, + UPDATE_BATTERY_LEVEL, + REPORT_LOW_BATTERY_WARNING, + REPORT_READER_EVENT, } = NativeModules.StripeTerminalReactNative.getConstants(); const NOT_INITIALIZED_ERROR_MESSAGE = @@ -154,6 +158,9 @@ export function useStripeTerminal(props?: Props) { onDidForwardPaymentIntent, onDidForwardingFailure, onDidDisconnect, + onDidUpdateBatteryLevel, + onDidReportLowBatteryWarning, + onDidReportReaderEvent, } = props || {}; const _discoverReaders = useCallback( @@ -316,6 +323,24 @@ export function useStripeTerminal(props?: Props) { [onDidDisconnect] ); + const didUpdateBatteryLevel = useCallback( + ({ result }: { result: Reader.BatteryLevel }) => { + onDidUpdateBatteryLevel?.(result); + }, + [onDidUpdateBatteryLevel] + ); + + const didReportLowBatteryWarning = useCallback(() => { + onDidReportLowBatteryWarning?.(); + }, [onDidReportLowBatteryWarning]); + + const didReportReaderEvent = useCallback( + ({ result }: { result: ReaderEvent }) => { + onDidReportReaderEvent?.(result); + }, + [onDidReportReaderEvent] + ); + useListener(REPORT_AVAILABLE_UPDATE, didReportAvailableUpdate); useListener(START_INSTALLING_UPDATE, didStartInstallingUpdate); useListener(REPORT_UPDATE_PROGRESS, didReportReaderSoftwareUpdateProgress); @@ -342,6 +367,10 @@ export function useStripeTerminal(props?: Props) { useListener(DISCONNECT, didDisconnect); + useListener(UPDATE_BATTERY_LEVEL, didUpdateBatteryLevel); + useListener(REPORT_LOW_BATTERY_WARNING, didReportLowBatteryWarning); + useListener(REPORT_READER_EVENT, didReportReaderEvent); + const _initialize = useCallback(async () => { if (!initialize || typeof initialize !== 'function') { const errorMessage = diff --git a/src/types/Reader.ts b/src/types/Reader.ts index 4c8422a2..5212c0e0 100644 --- a/src/types/Reader.ts +++ b/src/types/Reader.ts @@ -58,6 +58,12 @@ export namespace Reader { export type BatteryStatus = 'critical' | 'low' | 'nominal' | 'unknown'; + export type BatteryLevel = { + batteryLevel: number; + batteryStatus: BatteryStatus; + isCharging: boolean; + }; + export type NetworkStatus = 'offline' | 'online'; export type SoftwareUpdate = { diff --git a/src/types/index.ts b/src/types/index.ts index b5776b30..bb4b2dcc 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -317,6 +317,8 @@ export type OfflineStatus = { reader?: OfflineStatusDetails; }; +export type ReaderEvent = 'cardInserted' | 'cardRemoved'; + export type ConnectionStatus = 'notConnected' | 'connecting' | 'connected'; /** @@ -353,6 +355,10 @@ export type UserCallbacks = { onDidForwardingFailure?(error?: StripeError): void; onDidDisconnect?(reason?: Reader.DisconnectReason): void; + + onDidUpdateBatteryLevel?(result: Reader.BatteryLevel): void; + onDidReportLowBatteryWarning?(): void; + onDidReportReaderEvent?(event: ReaderEvent): void; }; export namespace PaymentMethod {