From 872e02e93cee1fe1a20ad2070285e618f321afc0 Mon Sep 17 00:00:00 2001 From: tim-lin-bbpos Date: Sat, 19 Oct 2024 02:59:51 +0800 Subject: [PATCH] Update collect input to use FormType variable (#834) * Update collect input * Keep existing attribute --- .../com/stripeterminalreactnative/Mappers.kt | 137 ++++++++++++------ .../callback/RNCollectInputResultCallback.kt | 3 +- ios/Mappers.swift | 30 +++- ios/Tests/MappersTests.swift | 10 +- src/types/index.ts | 43 +++++- 5 files changed, 164 insertions(+), 59 deletions(-) diff --git a/android/src/main/java/com/stripeterminalreactnative/Mappers.kt b/android/src/main/java/com/stripeterminalreactnative/Mappers.kt index e987e0ea..7c2586a5 100644 --- a/android/src/main/java/com/stripeterminalreactnative/Mappers.kt +++ b/android/src/main/java/com/stripeterminalreactnative/Mappers.kt @@ -66,7 +66,8 @@ import com.stripe.stripeterminal.external.models.Wallet import com.stripe.stripeterminal.external.models.WechatPayDetails import com.stripe.stripeterminal.log.LogLevel -internal fun getInt(map: ReadableMap, key: String): Int? = if (map.hasKey(key)) map.getInt(key) else null +internal fun getInt(map: ReadableMap, key: String): Int? = + if (map.hasKey(key)) map.getInt(key) else null internal fun getBoolean(map: ReadableMap?, key: String): Boolean = if (map?.hasKey(key) == true) map.getBoolean(key) else false @@ -200,50 +201,65 @@ internal fun mapToDiscoveryMethod(method: String?): DiscoveryMethod? { } @OptIn(OfflineMode::class) -internal fun mapFromPaymentIntent(paymentIntent: PaymentIntent, uuid: String): ReadableMap = nativeMapOf { - putString("id", paymentIntent.id) - putInt("amount", paymentIntent.amount.toInt()) - putString("captureMethod", paymentIntent.captureMethod) - putArray("charges", mapFromChargesList(paymentIntent.getCharges())) - putString("created", convertToUnixTimestamp(paymentIntent.created)) - putString("currency", paymentIntent.currency) - putMap( - "metadata", - nativeMapOf { - paymentIntent.metadata?.map { - putString(it.key, it.value) - } - } - ) - putString("statementDescriptor", paymentIntent.statementDescriptor) - putString("status", mapFromPaymentIntentStatus(paymentIntent.status)) - putMap("amountDetails", mapFromAmountDetails(paymentIntent.amountDetails)) - putInt("amountTip", paymentIntent.amountTip?.toInt() ?: 0) - putString("statementDescriptorSuffix", paymentIntent.statementDescriptorSuffix) - putString("sdkUuid", uuid) - putString("paymentMethodId", paymentIntent.paymentMethodId) - putMap("paymentMethod", paymentIntent.paymentMethod?.let { mapFromPaymentMethod(it) }) - putMap("offlineDetails", mapFromOfflineDetails(paymentIntent.offlineDetails)) - putMap("paymentMethodOptions",mapFromPaymentMethodOptions(paymentIntent.paymentMethodOptions)) -} - -internal fun mapFromPaymentMethodOptions(paymentMethodOptions: PaymentMethodOptions?): ReadableMap? = paymentMethodOptions?.let { +internal fun mapFromPaymentIntent(paymentIntent: PaymentIntent, uuid: String): ReadableMap = nativeMapOf { + putString("id", paymentIntent.id) + putInt("amount", paymentIntent.amount.toInt()) + putString("captureMethod", paymentIntent.captureMethod) + putArray("charges", mapFromChargesList(paymentIntent.getCharges())) + putString("created", convertToUnixTimestamp(paymentIntent.created)) + putString("currency", paymentIntent.currency) putMap( - "cardPresent", + "metadata", nativeMapOf { - putBoolean("requestExtendedAuthorization", it.cardPresent?.requestExtendedAuthorization ?: false) - putBoolean("requestIncrementalAuthorizationSupport",it.cardPresent?.requestIncrementalAuthorizationSupport ?: false) - putMap("surcharge", - nativeMapOf{ - putString("status",it.cardPresent?.surcharge?.status) - putIntOrNull(this,"maximumAmount",it.cardPresent?.surcharge?.maximumAmount?.toInt()) - } - ) + paymentIntent.metadata?.map { + putString(it.key, it.value) + } } ) + putString("statementDescriptor", paymentIntent.statementDescriptor) + putString("status", mapFromPaymentIntentStatus(paymentIntent.status)) + putMap("amountDetails", mapFromAmountDetails(paymentIntent.amountDetails)) + putInt("amountTip", paymentIntent.amountTip?.toInt() ?: 0) + putString("statementDescriptorSuffix", paymentIntent.statementDescriptorSuffix) + putString("sdkUuid", uuid) + putString("paymentMethodId", paymentIntent.paymentMethodId) + putMap("paymentMethod", paymentIntent.paymentMethod?.let { mapFromPaymentMethod(it) }) + putMap("offlineDetails", mapFromOfflineDetails(paymentIntent.offlineDetails)) + putMap( + "paymentMethodOptions", + mapFromPaymentMethodOptions(paymentIntent.paymentMethodOptions) + ) + } + +internal fun mapFromPaymentMethodOptions(paymentMethodOptions: PaymentMethodOptions?): ReadableMap? = + paymentMethodOptions?.let { + nativeMapOf { + putMap( + "cardPresent", + nativeMapOf { + putBoolean( + "requestExtendedAuthorization", + it.cardPresent?.requestExtendedAuthorization ?: false + ) + putBoolean( + "requestIncrementalAuthorizationSupport", + it.cardPresent?.requestIncrementalAuthorizationSupport ?: false + ) + putMap("surcharge", + nativeMapOf { + putString("status", it.cardPresent?.surcharge?.status) + putIntOrNull( + this, + "maximumAmount", + it.cardPresent?.surcharge?.maximumAmount?.toInt() + ) + } + ) + } + ) + } } -} internal fun mapFromSetupIntent(setupIntent: SetupIntent, uuid: String): ReadableMap = nativeMapOf { putString("created", convertToUnixTimestamp(setupIntent.created)) @@ -259,7 +275,7 @@ internal fun mapFromSetupIntent(setupIntent: SetupIntent, uuid: String): Readabl putMap( "metadata", nativeMapOf { - setupIntent.metadata?.map { + setupIntent.metadata.map { putString(it.key, it.value) } } @@ -688,7 +704,11 @@ internal fun mapFromWallet(wallet: Wallet?): ReadableMap = private fun convertListToReadableArray(list: List?): ReadableArray? { return list?.let { - WritableNativeArray().apply { for (item in list) { pushString(item) } } + WritableNativeArray().apply { + for (item in list) { + pushString(item) + } + } } } @@ -754,7 +774,9 @@ fun mapFromReaderDisconnectReason(reason: DisconnectReason): String { DisconnectReason.CRITICALLY_LOW_BATTERY -> "criticallyLowBattery" DisconnectReason.POWERED_OFF -> "poweredOff" DisconnectReason.BLUETOOTH_DISABLED -> "bluetoothDisabled" - else -> { "unknown" } + else -> { + "unknown" + } } } @@ -779,6 +801,18 @@ internal fun mapFromReaderSettings(settings: ReaderSettings): ReadableMap { } } +@OptIn(CollectInputs::class) +private fun CollectInputsResult.getFormType(): String { + return when (this) { + is EmailResult -> "email" + is NumericResult -> "numeric" + is PhoneResult -> "phone" + is SelectionResult -> "selection" + is SignatureResult -> "signature" + is TextResult -> "text" + } +} + @OptIn(CollectInputs::class) fun mapFromCollectInputsResults(results: List): ReadableArray { return nativeArrayOf { @@ -788,6 +822,7 @@ fun mapFromCollectInputsResults(results: List): ReadableArr nativeMapOf { putBoolean("skipped", it.skipped) putString("email", it.email) + putString("formType", it.getFormType()) putArray( "toggles", nativeArrayOf { @@ -798,10 +833,12 @@ fun mapFromCollectInputsResults(results: List): ReadableArr ) } ) + is NumericResult -> pushMap( nativeMapOf { putBoolean("skipped", it.skipped) putString("numericString", it.numericString) + putString("formType", it.getFormType()) putArray( "toggles", nativeArrayOf { @@ -812,10 +849,12 @@ fun mapFromCollectInputsResults(results: List): ReadableArr ) } ) + is PhoneResult -> pushMap( nativeMapOf { putBoolean("skipped", it.skipped) putString("phone", it.phone) + putString("formType", it.getFormType()) putArray( "toggles", nativeArrayOf { @@ -826,10 +865,12 @@ fun mapFromCollectInputsResults(results: List): ReadableArr ) } ) + is SelectionResult -> pushMap( nativeMapOf { putBoolean("skipped", it.skipped) putString("selection", it.selection) + putString("formType", it.getFormType()) putArray( "toggles", nativeArrayOf { @@ -840,10 +881,12 @@ fun mapFromCollectInputsResults(results: List): ReadableArr ) } ) + is SignatureResult -> pushMap( nativeMapOf { putBoolean("skipped", it.skipped) putString("signatureSvg", it.signatureSvg) + putString("formType", it.getFormType()) putArray( "toggles", nativeArrayOf { @@ -854,10 +897,12 @@ fun mapFromCollectInputsResults(results: List): ReadableArr ) } ) + is TextResult -> pushMap( nativeMapOf { putBoolean("skipped", it.skipped) putString("text", it.text) + putString("formType", it.getFormType()) putArray( "toggles", nativeArrayOf { @@ -879,7 +924,9 @@ fun mapFromToggleResult(toggleResult: ToggleResult): String { ToggleResult.ENABLED -> "enabled" ToggleResult.DISABLED -> "disabled" ToggleResult.SKIPPED -> "skipped" - else -> { "unknown" } + else -> { + "unknown" + } } } @@ -895,7 +942,9 @@ fun mapFromBatteryStatus(status: BatteryStatus): String { BatteryStatus.LOW -> "LOW" BatteryStatus.NOMINAL -> "NOMINAL" BatteryStatus.UNKNOWN -> "UNKNOWN" - else -> { "UNKNOWN" } + else -> { + "UNKNOWN" + } } } diff --git a/android/src/main/java/com/stripeterminalreactnative/callback/RNCollectInputResultCallback.kt b/android/src/main/java/com/stripeterminalreactnative/callback/RNCollectInputResultCallback.kt index 01f7d571..a2d46698 100644 --- a/android/src/main/java/com/stripeterminalreactnative/callback/RNCollectInputResultCallback.kt +++ b/android/src/main/java/com/stripeterminalreactnative/callback/RNCollectInputResultCallback.kt @@ -3,8 +3,7 @@ package com.stripeterminalreactnative.callback import com.facebook.react.bridge.Promise import com.stripe.stripeterminal.external.CollectInputs import com.stripe.stripeterminal.external.callable.CollectInputsResultCallback -import com.stripe.stripeterminal.external.models.CollectInputsResult -import com.stripe.stripeterminal.external.models.TerminalException +import com.stripe.stripeterminal.external.models.* import com.stripeterminalreactnative.createError import com.stripeterminalreactnative.mapFromCollectInputsResults import com.stripeterminalreactnative.nativeMapOf diff --git a/ios/Mappers.swift b/ios/Mappers.swift index d319d6d0..b34647e3 100644 --- a/ios/Mappers.swift +++ b/ios/Mappers.swift @@ -853,32 +853,50 @@ class Mappers { return list } + class func mapFormType(result: CollectInputsResult) -> String { + return if result is EmailResult { + "email" + } else if result is PhoneResult { + "phone" + } else if result is TextResult { + "text" + } else if result is NumericResult { + "numeric" + } else if result is SignatureResult { + "signature" + } else if result is SelectionResult { + "selection" + } else { + "" + } + } + class func mapFromCollectInputsResults(_ results: [CollectInputsResult]) -> NSDictionary { var collectInputResults: [NSDictionary] = [] for result in results { if result is EmailResult { let result = result as! EmailResult - var emailResult: NSDictionary = ["skipped": result.skipped, "email": result.email ?? "", "toggles": mapFromToggleResultList(result.toggles)] + let emailResult: NSDictionary = ["skipped": result.skipped, "email": result.email ?? "", "formType": mapFormType(result: result), "toggles": mapFromToggleResultList(result.toggles)] collectInputResults.append(emailResult) } else if result is PhoneResult { let result = result as! PhoneResult - var phoneResult: NSDictionary = ["skipped": result.skipped, "phone": result.phone ?? "", "toggles": mapFromToggleResultList(result.toggles)] + let phoneResult: NSDictionary = ["skipped": result.skipped, "phone": result.phone ?? "", "formType": mapFormType(result: result), "toggles": mapFromToggleResultList(result.toggles)] collectInputResults.append(phoneResult) } else if result is TextResult { let result = result as! TextResult - var textResult: NSDictionary = ["skipped": result.skipped, "text": result.text ?? "", "toggles": mapFromToggleResultList(result.toggles)] + let textResult: NSDictionary = ["skipped": result.skipped, "text": result.text ?? "", "formType": mapFormType(result: result), "toggles": mapFromToggleResultList(result.toggles)] collectInputResults.append(textResult) } else if result is NumericResult { let result = result as! NumericResult - var numericResult: NSDictionary = ["skipped": result.skipped, "numericString": result.numericString ?? "", "toggles": mapFromToggleResultList(result.toggles)] + let numericResult: NSDictionary = ["skipped": result.skipped, "numericString": result.numericString ?? "", "formType": mapFormType(result: result), "toggles": mapFromToggleResultList(result.toggles)] collectInputResults.append(numericResult) } else if result is SignatureResult { let result = result as! SignatureResult - var signatureResult: NSDictionary = ["skipped": result.skipped, "signatureSvg": result.signatureSvg ?? "", "toggles": mapFromToggleResultList(result.toggles)] + let signatureResult: NSDictionary = ["skipped": result.skipped, "signatureSvg": result.signatureSvg ?? "", "formType": mapFormType(result: result), "toggles": mapFromToggleResultList(result.toggles)] collectInputResults.append(signatureResult) } else if result is SelectionResult { let result = result as! SelectionResult - var selectionResult: NSDictionary = ["skipped": result.skipped, "selection": result.selection ?? "", "toggles": mapFromToggleResultList(result.toggles)] + let selectionResult: NSDictionary = ["skipped": result.skipped, "selection": result.selection ?? "", "formType": mapFormType(result: result), "toggles": mapFromToggleResultList(result.toggles)] collectInputResults.append(selectionResult) } } diff --git a/ios/Tests/MappersTests.swift b/ios/Tests/MappersTests.swift index a8e9339c..7a40479e 100644 --- a/ios/Tests/MappersTests.swift +++ b/ios/Tests/MappersTests.swift @@ -60,14 +60,16 @@ final class MappersTests: XCTestCase { guard let skipped = result["skipped"] as? Bool, let toggles = result["toggles"] as? [String], + let formType = result["formType"] as? String, let text = result["text"] as? String else { - XCTFail("CollectInput TestResult should have had text, skipped and toggles") + XCTFail("CollectInput TestResult should have had text, formType, skipped and toggles") return } XCTAssertFalse(skipped) XCTAssertEqual(toggles.count, 2) XCTAssertEqual(toggles[0], "enabled") XCTAssertEqual(toggles[1], "skipped") + XCTAssertEqual(formType, "text") XCTAssertEqual(text, "Written text from the reader") output = Mappers.mapFromCollectInputsResults([ @@ -89,6 +91,12 @@ final class MappersTests: XCTestCase { XCTAssertTrue(results[2][testEmail] != nil) XCTAssertTrue(results[3][testSelection] != nil) XCTAssertTrue(results[4][testSignatureSvg] != nil) + + XCTAssertTrue(results[0]["formType"] as! String == "numeric") + XCTAssertTrue(results[1]["formType"] as! String == "phone") + XCTAssertTrue(results[2]["formType"] as! String == "email") + XCTAssertTrue(results[3]["formType"] as! String == "selection") + XCTAssertTrue(results[4]["formType"] as! String == "signature") for result in results { if ((result.object(forKey: testNumericString)) != nil) { diff --git a/src/types/index.ts b/src/types/index.ts index a4d642c7..727a319a 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -449,15 +449,46 @@ export interface ICollectInputsResults { export interface ICollectInputsResult { skipped: boolean; - email?: string; - numericString?: string; - phone?: string; - selection?: string; - signatureSvg?: string; - text?: string; + formType: FormType; toggles: ToggleResult[]; } +// Contains data collected from a selection form +export interface SelectionResult extends ICollectInputsResult { + // selected button. Null if the form was skipped. + selection?: string | null; +} + +// Contains data collected from a signature form +export interface SignatureResult extends ICollectInputsResult { + // signature in svg format. Null if the form was skipped. + signatureSvg?: string | null; +} + +// Contains data collected from a phone form +export interface PhoneResult extends ICollectInputsResult { + // the submitted phone number in E.164 format. Null if the form was skipped. + phone?: string | null; +} + +// Contains data collected from an email form +export interface EmailResult extends ICollectInputsResult { + // the submitted email. Null if the form was skipped. + email?: string | null; +} + +// Contains data collected from a text form +export interface TextResult extends ICollectInputsResult { + // the submitted text. Null if the form was skipped. + text?: string | null; +} + +// Contains data collected from an email form +export interface NumericResult extends ICollectInputsResult { + // the submitted number as a string. Null if the form was skipped. + numericString?: string | null; +} + export interface ISelectionButton { style: SelectionButtonStyle; text: string;