react-amwal-pay 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +33 -0
  3. package/ReactAmwalPay.podspec +20 -0
  4. package/android/build.gradle +95 -0
  5. package/android/gradle.properties +5 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/java/com/reactamwalpay/ReactAmwalPayModule.kt +115 -0
  8. package/android/src/main/java/com/reactamwalpay/ReactAmwalPayPackage.kt +33 -0
  9. package/ios/ReactAmwalPay.h +5 -0
  10. package/ios/ReactAmwalPay.mm +18 -0
  11. package/lib/module/AmwalPaySDK.js +82 -0
  12. package/lib/module/AmwalPaySDK.js.map +1 -0
  13. package/lib/module/NativeReactAmwalPay.js +26 -0
  14. package/lib/module/NativeReactAmwalPay.js.map +1 -0
  15. package/lib/module/index.js +31 -0
  16. package/lib/module/index.js.map +1 -0
  17. package/lib/module/network/NetworkClient.js +67 -0
  18. package/lib/module/network/NetworkClient.js.map +1 -0
  19. package/lib/module/package.json +1 -0
  20. package/lib/module/utils/SecureHashUtil.js +37 -0
  21. package/lib/module/utils/SecureHashUtil.js.map +1 -0
  22. package/lib/typescript/package.json +1 -0
  23. package/lib/typescript/src/AmwalPaySDK.d.ts +25 -0
  24. package/lib/typescript/src/AmwalPaySDK.d.ts.map +1 -0
  25. package/lib/typescript/src/NativeReactAmwalPay.d.ts +54 -0
  26. package/lib/typescript/src/NativeReactAmwalPay.d.ts.map +1 -0
  27. package/lib/typescript/src/index.d.ts +8 -0
  28. package/lib/typescript/src/index.d.ts.map +1 -0
  29. package/lib/typescript/src/network/NetworkClient.d.ts +11 -0
  30. package/lib/typescript/src/network/NetworkClient.d.ts.map +1 -0
  31. package/lib/typescript/src/utils/SecureHashUtil.d.ts +10 -0
  32. package/lib/typescript/src/utils/SecureHashUtil.d.ts.map +1 -0
  33. package/package.json +167 -0
  34. package/src/AmwalPaySDK.ts +98 -0
  35. package/src/NativeReactAmwalPay.ts +64 -0
  36. package/src/index.tsx +46 -0
  37. package/src/network/NetworkClient.ts +84 -0
  38. package/src/utils/SecureHashUtil.ts +45 -0
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 amr saied
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # react-amwal-pay
2
+
3
+ amwal pay
4
+
5
+ ## Installation
6
+
7
+ ```sh
8
+ npm install react-amwal-pay
9
+ ```
10
+
11
+ ## Usage
12
+
13
+
14
+ ```js
15
+ import { multiply } from 'react-amwal-pay';
16
+
17
+ // ...
18
+
19
+ const result = multiply(3, 7);
20
+ ```
21
+
22
+
23
+ ## Contributing
24
+
25
+ See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
26
+
27
+ ## License
28
+
29
+ MIT
30
+
31
+ ---
32
+
33
+ Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
@@ -0,0 +1,20 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = "ReactAmwalPay"
7
+ s.version = package["version"]
8
+ s.summary = package["description"]
9
+ s.homepage = package["homepage"]
10
+ s.license = package["license"]
11
+ s.authors = package["author"]
12
+
13
+ s.platforms = { :ios => min_ios_version_supported }
14
+ s.source = { :git => "https://.git", :tag => "#{s.version}" }
15
+
16
+ s.source_files = "ios/**/*.{h,m,mm,cpp}"
17
+ s.private_header_files = "ios/**/*.h"
18
+
19
+ install_modules_dependencies(s)
20
+ end
@@ -0,0 +1,95 @@
1
+ buildscript {
2
+ ext.getExtOrDefault = {name ->
3
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['ReactAmwalPay_' + name]
4
+ }
5
+
6
+ repositories {
7
+ google()
8
+ mavenCentral()
9
+ }
10
+
11
+ dependencies {
12
+ classpath "com.android.tools.build:gradle:8.7.3"
13
+ // noinspection DifferentKotlinGradleVersion
14
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
15
+ }
16
+ }
17
+
18
+
19
+ apply plugin: "com.android.library"
20
+ apply plugin: "kotlin-android"
21
+
22
+ apply plugin: "com.facebook.react"
23
+
24
+ def getExtOrIntegerDefault(name) {
25
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["ReactAmwalPay_" + name]).toInteger()
26
+ }
27
+
28
+ android {
29
+ namespace "com.reactamwalpay"
30
+
31
+ compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
32
+
33
+ defaultConfig {
34
+ minSdkVersion getExtOrIntegerDefault("minSdkVersion")
35
+ targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
36
+ }
37
+
38
+ buildFeatures {
39
+ buildConfig true
40
+ }
41
+
42
+ buildTypes {
43
+ release {
44
+ minifyEnabled false
45
+ shrinkResources false
46
+ }
47
+ }
48
+
49
+ lintOptions {
50
+ disable "GradleCompatible"
51
+ }
52
+
53
+ compileOptions {
54
+ sourceCompatibility JavaVersion.VERSION_1_8
55
+ targetCompatibility JavaVersion.VERSION_1_8
56
+ }
57
+
58
+ sourceSets {
59
+ main {
60
+ java.srcDirs += [
61
+ "generated/java",
62
+ "generated/jni"
63
+ ]
64
+ }
65
+ }
66
+ }
67
+
68
+ repositories {
69
+ mavenCentral()
70
+ google()
71
+ }
72
+ rootProject.allprojects { Project subproject ->
73
+ subproject.repositories {
74
+ maven { url uri("E:/react_amwal_pay/android/repo") }
75
+
76
+ maven { url = uri("https://storage.googleapis.com/download.flutter.io") }
77
+ }
78
+ }
79
+ def kotlin_version = getExtOrDefault("kotlinVersion")
80
+
81
+ dependencies {
82
+ implementation "com.facebook.react:react-android"
83
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
84
+ implementation("com.amwal-pay:amwal_sdk:1.0.91"){
85
+ exclude group: 'com.android.support', module: 'support-v4'
86
+ exclude group: 'com.android.support', module: 'design'
87
+ }
88
+
89
+ }
90
+
91
+ react {
92
+ jsRootDir = file("../src/")
93
+ libraryName = "ReactAmwalPay"
94
+ codegenJavaPackageName = "com.reactamwalpay"
95
+ }
@@ -0,0 +1,5 @@
1
+ ReactAmwalPay_kotlinVersion=2.0.0
2
+ ReactAmwalPay_minSdkVersion=24
3
+ ReactAmwalPay_targetSdkVersion=34
4
+ ReactAmwalPay_compileSdkVersion=35
5
+ ReactAmwalPay_ndkVersion=27.1.12297006
@@ -0,0 +1,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>
@@ -0,0 +1,115 @@
1
+ package com.reactamwalpay
2
+
3
+ import android.util.Log
4
+ import com.facebook.react.bridge.*
5
+ import com.facebook.react.module.annotations.ReactModule
6
+ import com.facebook.react.modules.core.DeviceEventManagerModule
7
+ import com.anwalpay.sdk.AmwalSDK
8
+ import org.json.JSONObject
9
+
10
+ @ReactModule(name = ReactAmwalPayModule.NAME)
11
+ class ReactAmwalPayModule(reactContext: ReactApplicationContext) :
12
+ NativeReactAmwalPaySpec(reactContext) {
13
+
14
+ private val amwalSDK = AmwalSDK()
15
+
16
+ override fun getName(): String {
17
+ return NAME
18
+ }
19
+
20
+
21
+
22
+ private fun sendEvent(eventName: String, params: WritableMap?) {
23
+ reactApplicationContext
24
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
25
+ .emit(eventName, params)
26
+ }
27
+
28
+ override fun initiate(config: ReadableMap) {
29
+ Log.d(NAME, "initiate called")
30
+ val activity = reactApplicationContext.currentActivity
31
+ if (activity == null) {
32
+ // Since we can't use Promise here (method signature must match the spec),
33
+ // we'll send an error event
34
+ val params = Arguments.createMap()
35
+ params.putString("type", "onResponse")
36
+ val errorData = Arguments.createMap()
37
+ errorData.putString("status", "ERROR")
38
+ errorData.putString("message", "Activity context is not available")
39
+ params.putMap("data", errorData)
40
+ sendEvent("AmwalPayEvent", params)
41
+ return
42
+ }
43
+
44
+ Log.d(NAME, "initiate got here")
45
+ try {
46
+ val sdkConfig = AmwalSDK.Config(
47
+ environment = AmwalSDK.Config.Environment.valueOf(config.getString("environment") ?: ""),
48
+ sessionToken = config.getString("sessionToken") ?: "",
49
+ currency = AmwalSDK.Config.Currency.valueOf(config.getString("currency") ?: ""),
50
+ amount = config.getString("amount") ?: "",
51
+ merchantId = config.getString("merchantId") ?: "",
52
+ terminalId = config.getString("terminalId") ?: "",
53
+ locale = java.util.Locale(config.getString("locale") ?: "en"),
54
+ customerId = if (config.hasKey("customerId")) config.getString("customerId") else null,
55
+ transactionType = AmwalSDK.Config.TransactionType.valueOf(config.getString("transactionType") ?: "")
56
+ )
57
+
58
+ // Ensure this runs on the UI thread
59
+ (reactApplicationContext.currentActivity ?: return).runOnUiThread {
60
+ amwalSDK.start(
61
+ activity,
62
+ sdkConfig,
63
+ onResponse = {
64
+ Log.d(NAME, "onResponse called")
65
+ val params = Arguments.createMap()
66
+ try {
67
+ val json = JSONObject(it.toString())
68
+ val dataMap = jsonToWritableMap(json)
69
+ params.putMap("data", dataMap)
70
+ } catch (e: Exception) {
71
+ params.putString("data", it.toString())
72
+ }
73
+ emitOnResponse(params)
74
+ },
75
+ onCustomerId = {
76
+ Log.d(NAME, "onCustomerId called")
77
+ emitOnCustomerId(it)
78
+ }
79
+ )
80
+ }
81
+ } catch (e: Exception) {
82
+ Log.e(NAME, "Error initializing AmwalSDK", e)
83
+ val params = Arguments.createMap()
84
+ params.putString("type", "onResponse")
85
+ val errorData = Arguments.createMap()
86
+ errorData.putString("status", "ERROR")
87
+ errorData.putString("message", e.message ?: "Unknown error")
88
+ params.putMap("data", errorData)
89
+ sendEvent("AmwalPayEvent", params)
90
+ }
91
+ }
92
+
93
+ // Helper function to convert JSONObject to WritableMap
94
+ private fun jsonToWritableMap(jsonObject: JSONObject): WritableMap {
95
+ val map = Arguments.createMap()
96
+ val keys = jsonObject.keys()
97
+ while (keys.hasNext()) {
98
+ val key = keys.next()
99
+ val value = jsonObject.get(key)
100
+ when (value) {
101
+ is JSONObject -> map.putMap(key, jsonToWritableMap(value))
102
+ is Boolean -> map.putBoolean(key, value)
103
+ is Int -> map.putInt(key, value)
104
+ is Double -> map.putDouble(key, value)
105
+ is String -> map.putString(key, value)
106
+ else -> map.putString(key, value.toString())
107
+ }
108
+ }
109
+ return map
110
+ }
111
+
112
+ companion object {
113
+ const val NAME = "ReactAmwalPay"
114
+ }
115
+ }
@@ -0,0 +1,33 @@
1
+ package com.reactamwalpay
2
+
3
+ import com.facebook.react.BaseReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.module.model.ReactModuleInfo
7
+ import com.facebook.react.module.model.ReactModuleInfoProvider
8
+ import java.util.HashMap
9
+
10
+ class ReactAmwalPayPackage : BaseReactPackage() {
11
+ override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
12
+ return if (name == ReactAmwalPayModule.NAME) {
13
+ ReactAmwalPayModule(reactContext)
14
+ } else {
15
+ null
16
+ }
17
+ }
18
+
19
+ override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
20
+ return ReactModuleInfoProvider {
21
+ val moduleInfos: MutableMap<String, ReactModuleInfo> = HashMap()
22
+ moduleInfos[ReactAmwalPayModule.NAME] = ReactModuleInfo(
23
+ ReactAmwalPayModule.NAME,
24
+ ReactAmwalPayModule.NAME,
25
+ false, // canOverrideExistingModule
26
+ false, // needsEagerInit
27
+ false, // isCxxModule
28
+ true // isTurboModule
29
+ )
30
+ moduleInfos
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,5 @@
1
+ #import <ReactAmwalPaySpec/ReactAmwalPaySpec.h>
2
+
3
+ @interface ReactAmwalPay : NSObject <NativeReactAmwalPaySpec>
4
+
5
+ @end
@@ -0,0 +1,18 @@
1
+ #import "ReactAmwalPay.h"
2
+
3
+ @implementation ReactAmwalPay
4
+ RCT_EXPORT_MODULE()
5
+
6
+ - (NSNumber *)multiply:(double)a b:(double)b {
7
+ NSNumber *result = @(a * b);
8
+
9
+ return result;
10
+ }
11
+
12
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
13
+ (const facebook::react::ObjCTurboModule::InitParams &)params
14
+ {
15
+ return std::make_shared<facebook::react::NativeReactAmwalPaySpecJSI>(params);
16
+ }
17
+
18
+ @end
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+
3
+ import { initiate, onCustomerId, onResponse } from "./index.js";
4
+ import NetworkClient from "./network/NetworkClient.js";
5
+ class AmwalPaySDK {
6
+ onResponseSubscription = null;
7
+ onCustomerIdSubscription = null;
8
+ constructor() {
9
+ // Initialize the event emitter
10
+ }
11
+ static getInstance() {
12
+ if (!AmwalPaySDK.instance) {
13
+ AmwalPaySDK.instance = new AmwalPaySDK();
14
+ }
15
+ return AmwalPaySDK.instance;
16
+ }
17
+
18
+ /**
19
+ * Initiates the payment process by first fetching a session token and then starting the payment flow
20
+ * @param config The payment configuration
21
+ */
22
+ async startPayment(config) {
23
+ try {
24
+ // Set up event listeners before starting the payment process
25
+ this.setupEventListeners(config);
26
+
27
+ // Get network client instance
28
+ const networkClient = NetworkClient.getInstance();
29
+
30
+ // Fetch session token
31
+ const sessionToken = await networkClient.fetchSessionToken(config.environment, config.merchantId, config.customerId, config.secureHash);
32
+ if (!sessionToken) {
33
+ // If session token is null, the error has already been shown by NetworkClient
34
+ return;
35
+ }
36
+
37
+ // Create complete config with session token
38
+ const completeConfig = {
39
+ ...config,
40
+ sessionToken
41
+ };
42
+
43
+ // Initiate the payment process
44
+ initiate(completeConfig);
45
+ } catch (error) {
46
+ console.error('Error starting payment:', error);
47
+ }
48
+ }
49
+ dispose() {
50
+ // Remove all event listeners
51
+ this.removeEventListeners();
52
+ }
53
+
54
+ /**
55
+ * Sets up event listeners for AmwalPay events
56
+ * @param config The payment configuration containing callback functions
57
+ */
58
+ setupEventListeners(config) {
59
+ // Remove any existing listeners
60
+ this.removeEventListeners();
61
+ this.onResponseSubscription = onResponse(response => {
62
+ console.log('Received AmwalPayResponse:', response);
63
+ config.onResponse(response);
64
+ });
65
+ this.onCustomerIdSubscription = onCustomerId(customerId => {
66
+ console.log('Received customerId:', customerId);
67
+ config.onCustomerId(customerId);
68
+ });
69
+ }
70
+
71
+ /**
72
+ * Removes all event listeners
73
+ */
74
+ removeEventListeners() {
75
+ this.onResponseSubscription?.remove();
76
+ this.onCustomerIdSubscription?.remove();
77
+ this.onResponseSubscription = null;
78
+ this.onCustomerIdSubscription = null;
79
+ }
80
+ }
81
+ export default AmwalPaySDK;
82
+ //# sourceMappingURL=AmwalPaySDK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["initiate","onCustomerId","onResponse","NetworkClient","AmwalPaySDK","onResponseSubscription","onCustomerIdSubscription","constructor","getInstance","instance","startPayment","config","setupEventListeners","networkClient","sessionToken","fetchSessionToken","environment","merchantId","customerId","secureHash","completeConfig","error","console","dispose","removeEventListeners","response","log","remove"],"sourceRoot":"..\\..\\src","sources":["AmwalPaySDK.ts"],"mappings":";;AAAA,SAASA,QAAQ,EAAEC,YAAY,EAAEC,UAAU,QAA6B,YAAS;AACjF,OAAOC,aAAa,MAAM,4BAAyB;AAInD,MAAMC,WAAW,CAAC;EAGRC,sBAAsB,GAA2B,IAAI;EAErDC,wBAAwB,GAA2B,IAAI;EAEvDC,WAAWA,CAAA,EAAG;IACpB;EAAA;EAIF,OAAOC,WAAWA,CAAA,EAAgB;IAChC,IAAI,CAACJ,WAAW,CAACK,QAAQ,EAAE;MACzBL,WAAW,CAACK,QAAQ,GAAG,IAAIL,WAAW,CAAC,CAAC;IAC1C;IACA,OAAOA,WAAW,CAACK,QAAQ;EAC7B;;EAEA;AACF;AACA;AACA;EACE,MAAMC,YAAYA,CAACC,MAA4C,EAAiB;IAC9E,IAAI;MACF;MACA,IAAI,CAACC,mBAAmB,CAACD,MAAM,CAAC;;MAEhC;MACA,MAAME,aAAa,GAAGV,aAAa,CAACK,WAAW,CAAC,CAAC;;MAEjD;MACA,MAAMM,YAAY,GAAG,MAAMD,aAAa,CAACE,iBAAiB,CACxDJ,MAAM,CAACK,WAAW,EAClBL,MAAM,CAACM,UAAU,EACjBN,MAAM,CAACO,UAAU,EACjBP,MAAM,CAACQ,UACT,CAAC;MAED,IAAI,CAACL,YAAY,EAAE;QACjB;QACA;MACF;;MAEA;MACA,MAAMM,cAA8B,GAAG;QACrC,GAAGT,MAAM;QACTG;MACF,CAAC;;MAED;MACAd,QAAQ,CAACoB,cAAc,CAAC;IAC1B,CAAC,CAAC,OAAOC,KAAK,EAAE;MACdC,OAAO,CAACD,KAAK,CAAC,yBAAyB,EAAEA,KAAK,CAAC;IACjD;EACF;EAEAE,OAAOA,CAAA,EAAS;IACd;IACA,IAAI,CAACC,oBAAoB,CAAC,CAAC;EAC7B;;EAEA;AACF;AACA;AACA;EACUZ,mBAAmBA,CAACD,MAA4C,EAAQ;IAC9E;IACA,IAAI,CAACa,oBAAoB,CAAC,CAAC;IAE3B,IAAI,CAACnB,sBAAsB,GAAGH,UAAU,CAAEuB,QAAQ,IAAK;MACrDH,OAAO,CAACI,GAAG,CAAC,4BAA4B,EAAED,QAAQ,CAAC;MACnDd,MAAM,CAACT,UAAU,CAACuB,QAAQ,CAAC;IAC7B,CAAC,CAAC;IAEF,IAAI,CAACnB,wBAAwB,GAAGL,YAAY,CAAEiB,UAAU,IAAK;MAC3DI,OAAO,CAACI,GAAG,CAAC,sBAAsB,EAAER,UAAU,CAAC;MAC/CP,MAAM,CAACV,YAAY,CAACiB,UAAU,CAAC;IACjC,CAAC,CAAC;EACJ;;EAEA;AACF;AACA;EACUM,oBAAoBA,CAAA,EAAS;IACnC,IAAI,CAACnB,sBAAsB,EAAEsB,MAAM,CAAC,CAAC;IACrC,IAAI,CAACrB,wBAAwB,EAAEqB,MAAM,CAAC,CAAC;IACvC,IAAI,CAACtB,sBAAsB,GAAG,IAAI;IAClC,IAAI,CAACC,wBAAwB,GAAG,IAAI;EACtC;AACF;AAEA,eAAeF,WAAW","ignoreList":[]}
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+
3
+ import { TurboModuleRegistry } from 'react-native';
4
+ export let Environment = /*#__PURE__*/function (Environment) {
5
+ Environment["SIT"] = "SIT";
6
+ Environment["UAT"] = "UAT";
7
+ Environment["PROD"] = "PROD";
8
+ return Environment;
9
+ }({});
10
+ export let Currency = /*#__PURE__*/function (Currency) {
11
+ Currency["OMR"] = "OMR";
12
+ return Currency;
13
+ }({});
14
+ export let TransactionType = /*#__PURE__*/function (TransactionType) {
15
+ TransactionType["NFC"] = "NFC";
16
+ TransactionType["CARD_WALLET"] = "CARD_WALLET";
17
+ TransactionType["APPLE_PAY"] = "APPLE_PAY";
18
+ return TransactionType;
19
+ }({});
20
+
21
+ // This interface is for JavaScript side only, not for the native module spec
22
+
23
+ // This is the configuration that will be passed to the native module
24
+
25
+ export default TurboModuleRegistry.getEnforcing('ReactAmwalPay');
26
+ //# sourceMappingURL=NativeReactAmwalPay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["TurboModuleRegistry","Environment","Currency","TransactionType","getEnforcing"],"sourceRoot":"..\\..\\src","sources":["NativeReactAmwalPay.ts"],"mappings":";;AACA,SAASA,mBAAmB,QAAQ,cAAc;AAGlD,WAAYC,WAAW,0BAAXA,WAAW;EAAXA,WAAW;EAAXA,WAAW;EAAXA,WAAW;EAAA,OAAXA,WAAW;AAAA;AAMvB,WAAYC,QAAQ,0BAARA,QAAQ;EAARA,QAAQ;EAAA,OAARA,QAAQ;AAAA;AAIpB,WAAYC,eAAe,0BAAfA,eAAe;EAAfA,eAAe;EAAfA,eAAe;EAAfA,eAAe;EAAA,OAAfA,eAAe;AAAA;;AAY3B;;AAgBA;;AAqBA,eAAeH,mBAAmB,CAACI,YAAY,CAAO,eAAe,CAAC","ignoreList":[]}
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+
3
+ import ReactAmwalPay, { Environment, Currency, TransactionType } from "./NativeReactAmwalPay.js";
4
+ import AmwalPaySDK from "./AmwalPaySDK.js";
5
+ // Create an event emitter for the native module
6
+
7
+ export function initiate(config) {
8
+ const nativeConfig = {
9
+ environment: config.environment,
10
+ secureHash: config.secureHash,
11
+ currency: config.currency,
12
+ amount: config.amount,
13
+ merchantId: config.merchantId,
14
+ terminalId: config.terminalId,
15
+ locale: config.locale,
16
+ customerId: config.customerId,
17
+ transactionType: config.transactionType,
18
+ sessionToken: config.sessionToken
19
+ };
20
+
21
+ // Call the native module
22
+ ReactAmwalPay.initiate(nativeConfig);
23
+ }
24
+ export function onResponse(callback) {
25
+ return ReactAmwalPay.onResponse(callback);
26
+ }
27
+ export function onCustomerId(callback) {
28
+ return ReactAmwalPay.onCustomerId(callback);
29
+ }
30
+ export { Environment, Currency, TransactionType, AmwalPaySDK };
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["ReactAmwalPay","Environment","Currency","TransactionType","AmwalPaySDK","initiate","config","nativeConfig","environment","secureHash","currency","amount","merchantId","terminalId","locale","customerId","transactionType","sessionToken","onResponse","callback","onCustomerId"],"sourceRoot":"..\\..\\src","sources":["index.tsx"],"mappings":";;AAAA,OAAOA,aAAa,IAClBC,WAAW,EACXC,QAAQ,EACRC,eAAe,QAIV,0BAAuB;AAC9B,OAAOC,WAAW,MAAM,kBAAe;AAGvC;;AAEA,OAAO,SAASC,QAAQA,CAACC,MAAsB,EAAQ;EACrD,MAAMC,YAAkC,GAAG;IACzCC,WAAW,EAAEF,MAAM,CAACE,WAAW;IAC/BC,UAAU,EAAEH,MAAM,CAACG,UAAU;IAC7BC,QAAQ,EAAEJ,MAAM,CAACI,QAAQ;IACzBC,MAAM,EAAEL,MAAM,CAACK,MAAM;IACrBC,UAAU,EAAEN,MAAM,CAACM,UAAU;IAC7BC,UAAU,EAAEP,MAAM,CAACO,UAAU;IAC7BC,MAAM,EAAER,MAAM,CAACQ,MAAM;IACrBC,UAAU,EAAET,MAAM,CAACS,UAAU;IAC7BC,eAAe,EAAEV,MAAM,CAACU,eAAe;IACvCC,YAAY,EAAEX,MAAM,CAACW;EACvB,CAAC;;EAED;EACAjB,aAAa,CAACK,QAAQ,CAACE,YAAY,CAAC;AACtC;AAEA,OAAO,SAASW,UAAUA,CAACC,QAA8C,EAAoB;EAC3F,OAAOnB,aAAa,CAACkB,UAAU,CAACC,QAAQ,CAAC;AAC3C;AACA,OAAO,SAASC,YAAYA,CAACD,QAAsC,EAAoB;EACrF,OAAOnB,aAAa,CAACoB,YAAY,CAACD,QAAQ,CAAC;AAC7C;AAEA,SACElB,WAAW,EACXC,QAAQ,EACRC,eAAe,EAGfC,WAAW","ignoreList":[]}
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+
3
+ import { Alert } from 'react-native';
4
+ import { Environment } from "../NativeReactAmwalPay.js";
5
+ import SecureHashUtil from "../utils/SecureHashUtil.js";
6
+ class NetworkClient {
7
+ constructor() {}
8
+ static getInstance() {
9
+ if (!NetworkClient.instance) {
10
+ NetworkClient.instance = new NetworkClient();
11
+ }
12
+ return NetworkClient.instance;
13
+ }
14
+ getWebhookUrl(env) {
15
+ switch (env) {
16
+ case Environment.SIT:
17
+ return 'https://test.amwalpg.com:24443/';
18
+ case Environment.UAT:
19
+ return 'https://test.amwalpg.com:14443/';
20
+ case Environment.PROD:
21
+ return 'https://webhook.amwalpg.com/';
22
+ default:
23
+ return 'https://test.amwalpg.com:24443/';
24
+ }
25
+ }
26
+ async fetchSessionToken(env, merchantId, customerId, secureHashValue) {
27
+ try {
28
+ const webhookUrl = this.getWebhookUrl(env);
29
+ const dataMap = {
30
+ merchantId,
31
+ customerId
32
+ };
33
+ const secureHash = SecureHashUtil.clearSecureHash(secureHashValue, dataMap);
34
+ const response = await fetch(`${webhookUrl}Membership/GetSDKSessionToken`, {
35
+ method: 'POST',
36
+ headers: {
37
+ 'Accept': 'text/plain',
38
+ 'Accept-Language': 'en-US,en;q=0.9',
39
+ 'Content-Type': 'application/json'
40
+ },
41
+ body: JSON.stringify({
42
+ merchantId,
43
+ secureHashValue: secureHash,
44
+ customerId
45
+ })
46
+ });
47
+ const responseData = await response.json();
48
+ if (response.ok && responseData.success) {
49
+ return responseData.data.sessionToken;
50
+ } else {
51
+ const errorMessage = responseData.errorList?.join(',') || 'Unknown error';
52
+ this.showErrorDialog(errorMessage);
53
+ return null;
54
+ }
55
+ } catch (error) {
56
+ this.showErrorDialog('Something Went Wrong');
57
+ return null;
58
+ }
59
+ }
60
+ showErrorDialog(message) {
61
+ Alert.alert('Error', message, [{
62
+ text: 'OK'
63
+ }]);
64
+ }
65
+ }
66
+ export default NetworkClient;
67
+ //# sourceMappingURL=NetworkClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["Alert","Environment","SecureHashUtil","NetworkClient","constructor","getInstance","instance","getWebhookUrl","env","SIT","UAT","PROD","fetchSessionToken","merchantId","customerId","secureHashValue","webhookUrl","dataMap","secureHash","clearSecureHash","response","fetch","method","headers","body","JSON","stringify","responseData","json","ok","success","data","sessionToken","errorMessage","errorList","join","showErrorDialog","error","message","alert","text"],"sourceRoot":"..\\..\\..\\src","sources":["network/NetworkClient.ts"],"mappings":";;AAAA,SAASA,KAAK,QAAQ,cAAc;AACpC,SAASC,WAAW,QAAQ,2BAAwB;AACpD,OAAOC,cAAc,MAAM,4BAAyB;AAEpD,MAAMC,aAAa,CAAC;EAGVC,WAAWA,CAAA,EAAG,CAAC;EAEvB,OAAOC,WAAWA,CAAA,EAAkB;IAClC,IAAI,CAACF,aAAa,CAACG,QAAQ,EAAE;MAC3BH,aAAa,CAACG,QAAQ,GAAG,IAAIH,aAAa,CAAC,CAAC;IAC9C;IACA,OAAOA,aAAa,CAACG,QAAQ;EAC/B;EAEQC,aAAaA,CAACC,GAAgB,EAAU;IAC9C,QAAQA,GAAG;MACT,KAAKP,WAAW,CAACQ,GAAG;QAClB,OAAO,iCAAiC;MAC1C,KAAKR,WAAW,CAACS,GAAG;QAClB,OAAO,iCAAiC;MAC1C,KAAKT,WAAW,CAACU,IAAI;QACnB,OAAO,8BAA8B;MACvC;QACE,OAAO,iCAAiC;IAC5C;EACF;EAEA,MAAMC,iBAAiBA,CACrBJ,GAAgB,EAChBK,UAAkB,EAClBC,UAAyB,EACzBC,eAAuB,EACC;IACxB,IAAI;MACF,MAAMC,UAAU,GAAG,IAAI,CAACT,aAAa,CAACC,GAAG,CAAC;MAE1C,MAAMS,OAAO,GAAG;QACdJ,UAAU;QACVC;MACF,CAAC;MAED,MAAMI,UAAU,GAAGhB,cAAc,CAACiB,eAAe,CAACJ,eAAe,EAAEE,OAAO,CAAC;MAE3E,MAAMG,QAAQ,GAAG,MAAMC,KAAK,CAAC,GAAGL,UAAU,+BAA+B,EAAE;QACzEM,MAAM,EAAE,MAAM;QACdC,OAAO,EAAE;UACP,QAAQ,EAAE,YAAY;UACtB,iBAAiB,EAAE,gBAAgB;UACnC,cAAc,EAAE;QAClB,CAAC;QACDC,IAAI,EAAEC,IAAI,CAACC,SAAS,CAAC;UACnBb,UAAU;UACVE,eAAe,EAAEG,UAAU;UAC3BJ;QACF,CAAC;MACH,CAAC,CAAC;MAEF,MAAMa,YAAY,GAAG,MAAMP,QAAQ,CAACQ,IAAI,CAAC,CAAC;MAE1C,IAAIR,QAAQ,CAACS,EAAE,IAAIF,YAAY,CAACG,OAAO,EAAE;QACvC,OAAOH,YAAY,CAACI,IAAI,CAACC,YAAY;MACvC,CAAC,MAAM;QACL,MAAMC,YAAY,GAAGN,YAAY,CAACO,SAAS,EAAEC,IAAI,CAAC,GAAG,CAAC,IAAI,eAAe;QACzE,IAAI,CAACC,eAAe,CAACH,YAAY,CAAC;QAClC,OAAO,IAAI;MACb;IACF,CAAC,CAAC,OAAOI,KAAK,EAAE;MACd,IAAI,CAACD,eAAe,CAAC,sBAAsB,CAAC;MAC5C,OAAO,IAAI;IACb;EACF;EAEQA,eAAeA,CAACE,OAAe,EAAQ;IAC7CtC,KAAK,CAACuC,KAAK,CACT,OAAO,EACPD,OAAO,EACP,CAAC;MAAEE,IAAI,EAAE;IAAK,CAAC,CACjB,CAAC;EACH;AACF;AAEA,eAAerC,aAAa","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+
3
+ import HmacSHA256 from 'crypto-js/hmac-sha256';
4
+ import Hex from 'crypto-js/enc-hex';
5
+ class SecureHashUtil {
6
+ static clearSecureHash(secretKey, data) {
7
+ delete data.secureHashValue;
8
+ const concatenatedString = this.composeData(data);
9
+ return this.generateSecureHash(concatenatedString, secretKey);
10
+ }
11
+ static composeData(requestParameters) {
12
+ return Object.entries(requestParameters).sort(([keyA], [keyB]) => keyA.localeCompare(keyB)).filter(([_, value]) => value != null && value !== '').map(([key, value]) => `${key}=${value}`).join('&');
13
+ }
14
+ static generateSecureHash(message, secretKey) {
15
+ try {
16
+ // Convert hex string to byte array
17
+ const keyBytes = secretKey.match(/.{2}/g)?.map(byte => parseInt(byte, 16));
18
+ if (!keyBytes) {
19
+ throw new Error('Invalid secret key format');
20
+ }
21
+
22
+ // Convert key bytes to hex string for crypto-js
23
+ const keyHex = keyBytes.map(byte => byte.toString(16).padStart(2, '0')).join('');
24
+
25
+ // Generate HMAC-SHA256
26
+ const hash = HmacSHA256(message, Hex.parse(keyHex));
27
+
28
+ // Convert to uppercase hex string
29
+ return hash.toString(Hex).toUpperCase();
30
+ } catch (e) {
31
+ console.error('Error generating secure hash:', e);
32
+ return '';
33
+ }
34
+ }
35
+ }
36
+ export default SecureHashUtil;
37
+ //# sourceMappingURL=SecureHashUtil.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["HmacSHA256","Hex","SecureHashUtil","clearSecureHash","secretKey","data","secureHashValue","concatenatedString","composeData","generateSecureHash","requestParameters","Object","entries","sort","keyA","keyB","localeCompare","filter","_","value","map","key","join","message","keyBytes","match","byte","parseInt","Error","keyHex","toString","padStart","hash","parse","toUpperCase","e","console","error"],"sourceRoot":"..\\..\\..\\src","sources":["utils/SecureHashUtil.ts"],"mappings":";;AAAA,OAAOA,UAAU,MAAM,uBAAuB;AAC9C,OAAOC,GAAG,MAAM,mBAAmB;AAInC,MAAMC,cAAc,CAAC;EACnB,OAAOC,eAAeA,CAACC,SAAiB,EAAEC,IAAa,EAAU;IAC/D,OAAOA,IAAI,CAACC,eAAe;IAC3B,MAAMC,kBAAkB,GAAG,IAAI,CAACC,WAAW,CAACH,IAAI,CAAC;IACjD,OAAO,IAAI,CAACI,kBAAkB,CAACF,kBAAkB,EAAEH,SAAS,CAAC;EAC/D;EAEA,OAAeI,WAAWA,CAACE,iBAA0B,EAAU;IAC7D,OAAOC,MAAM,CAACC,OAAO,CAACF,iBAAiB,CAAC,CACrCG,IAAI,CAAC,CAAC,CAACC,IAAI,CAAC,EAAE,CAACC,IAAI,CAAC,KAAKD,IAAI,CAACE,aAAa,CAACD,IAAI,CAAC,CAAC,CAClDE,MAAM,CAAC,CAAC,CAACC,CAAC,EAAEC,KAAK,CAAC,KAAKA,KAAK,IAAI,IAAI,IAAIA,KAAK,KAAK,EAAE,CAAC,CACrDC,GAAG,CAAC,CAAC,CAACC,GAAG,EAAEF,KAAK,CAAC,KAAK,GAAGE,GAAG,IAAIF,KAAK,EAAE,CAAC,CACxCG,IAAI,CAAC,GAAG,CAAC;EACd;EAEA,OAAeb,kBAAkBA,CAACc,OAAe,EAAEnB,SAAiB,EAAU;IAC5E,IAAI;MACF;MACA,MAAMoB,QAAQ,GAAGpB,SAAS,CAACqB,KAAK,CAAC,OAAO,CAAC,EAAEL,GAAG,CAACM,IAAI,IAAIC,QAAQ,CAACD,IAAI,EAAE,EAAE,CAAC,CAAC;MAE1E,IAAI,CAACF,QAAQ,EAAE;QACb,MAAM,IAAII,KAAK,CAAC,2BAA2B,CAAC;MAC9C;;MAEA;MACA,MAAMC,MAAM,GAAGL,QAAQ,CAACJ,GAAG,CAACM,IAAI,IAAIA,IAAI,CAACI,QAAQ,CAAC,EAAE,CAAC,CAACC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAACT,IAAI,CAAC,EAAE,CAAC;;MAEhF;MACA,MAAMU,IAAI,GAAGhC,UAAU,CAACuB,OAAO,EAAEtB,GAAG,CAACgC,KAAK,CAACJ,MAAM,CAAC,CAAC;;MAEnD;MACA,OAAOG,IAAI,CAACF,QAAQ,CAAC7B,GAAG,CAAC,CAACiC,WAAW,CAAC,CAAC;IACzC,CAAC,CAAC,OAAOC,CAAC,EAAE;MACVC,OAAO,CAACC,KAAK,CAAC,+BAA+B,EAAEF,CAAC,CAAC;MACjD,OAAO,EAAE;IACX;EACF;AACF;AAEA,eAAejC,cAAc","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,25 @@
1
+ import { type AmwalPayConfig } from './index';
2
+ declare class AmwalPaySDK {
3
+ private static instance;
4
+ private onResponseSubscription;
5
+ private onCustomerIdSubscription;
6
+ private constructor();
7
+ static getInstance(): AmwalPaySDK;
8
+ /**
9
+ * Initiates the payment process by first fetching a session token and then starting the payment flow
10
+ * @param config The payment configuration
11
+ */
12
+ startPayment(config: Omit<AmwalPayConfig, 'sessionToken'>): Promise<void>;
13
+ dispose(): void;
14
+ /**
15
+ * Sets up event listeners for AmwalPay events
16
+ * @param config The payment configuration containing callback functions
17
+ */
18
+ private setupEventListeners;
19
+ /**
20
+ * Removes all event listeners
21
+ */
22
+ private removeEventListeners;
23
+ }
24
+ export default AmwalPaySDK;
25
+ //# sourceMappingURL=AmwalPaySDK.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AmwalPaySDK.d.ts","sourceRoot":"","sources":["../../../src/AmwalPaySDK.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsC,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAKlF,cAAM,WAAW;IACf,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAc;IAErC,OAAO,CAAC,sBAAsB,CAAgC;IAE9D,OAAO,CAAC,wBAAwB,CAAgC;IAEhE,OAAO;IAKP,MAAM,CAAC,WAAW,IAAI,WAAW;IAOjC;;;OAGG;IACG,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,cAAc,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAkC/E,OAAO,IAAI,IAAI;IAKf;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAe3B;;OAEG;IACH,OAAO,CAAC,oBAAoB;CAM7B;AAED,eAAe,WAAW,CAAC"}
@@ -0,0 +1,54 @@
1
+ import type { TurboModule } from 'react-native';
2
+ import type { EventEmitter } from 'react-native/Libraries/Types/CodegenTypes';
3
+ export declare enum Environment {
4
+ SIT = "SIT",
5
+ UAT = "UAT",
6
+ PROD = "PROD"
7
+ }
8
+ export declare enum Currency {
9
+ OMR = "OMR"
10
+ }
11
+ export declare enum TransactionType {
12
+ NFC = "NFC",
13
+ CARD_WALLET = "CARD_WALLET",
14
+ APPLE_PAY = "APPLE_PAY"
15
+ }
16
+ export interface AmwalPayResponse {
17
+ status: string;
18
+ message: string;
19
+ data?: Object;
20
+ }
21
+ export interface AmwalPayConfig {
22
+ environment: Environment;
23
+ secureHash: string;
24
+ currency: Currency;
25
+ amount: string;
26
+ merchantId: string;
27
+ terminalId: string;
28
+ locale: string;
29
+ customerId: string | null;
30
+ transactionType: TransactionType;
31
+ sessionToken?: string;
32
+ onResponse: (response: AmwalPayResponse) => void;
33
+ onCustomerId: (customerId: string) => void;
34
+ }
35
+ export interface AmwalPayNativeConfig {
36
+ environment: string;
37
+ secureHash: string;
38
+ currency: string;
39
+ amount: string;
40
+ merchantId: string;
41
+ terminalId: string;
42
+ locale: string;
43
+ customerId: string | null;
44
+ transactionType: string;
45
+ sessionToken?: string;
46
+ }
47
+ export interface Spec extends TurboModule {
48
+ initiate(config: AmwalPayNativeConfig): void;
49
+ onResponse: EventEmitter<AmwalPayResponse>;
50
+ onCustomerId: EventEmitter<string>;
51
+ }
52
+ declare const _default: Spec;
53
+ export default _default;
54
+ //# sourceMappingURL=NativeReactAmwalPay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeReactAmwalPay.d.ts","sourceRoot":"","sources":["../../../src/NativeReactAmwalPay.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2CAA2C,CAAC;AAE9E,oBAAY,WAAW;IACrB,GAAG,QAAQ;IACX,GAAG,QAAQ;IACX,IAAI,SAAS;CACd;AAED,oBAAY,QAAQ;IAClB,GAAG,QAAQ;CACZ;AAED,oBAAY,eAAe;IACzB,GAAG,QAAO;IACV,WAAW,gBAAe;IAC1B,SAAS,cAAa;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAGD,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,WAAW,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,eAAe,EAAE,eAAe,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,CAAC,QAAQ,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACjD,YAAY,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5C;AAGD,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,IAAK,SAAQ,WAAW;IAEvC,QAAQ,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC7C,UAAU,EAAE,YAAY,CAAC,gBAAgB,CAAC,CAAC;IAC3C,YAAY,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;CACpC;;AAED,wBAAuE"}
@@ -0,0 +1,8 @@
1
+ import { Environment, Currency, TransactionType, type AmwalPayResponse, type AmwalPayConfig } from './NativeReactAmwalPay';
2
+ import AmwalPaySDK from './AmwalPaySDK';
3
+ import type { EventSubscription } from 'react-native';
4
+ export declare function initiate(config: AmwalPayConfig): void;
5
+ export declare function onResponse(callback: (response: AmwalPayResponse) => void): EventSubscription;
6
+ export declare function onCustomerId(callback: (customerId: string) => void): EventSubscription;
7
+ export { Environment, Currency, TransactionType, type AmwalPayResponse, type AmwalPayConfig, AmwalPaySDK, };
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAsB,EACpB,WAAW,EACX,QAAQ,EACR,eAAe,EACf,KAAK,gBAAgB,EACrB,KAAK,cAAc,EAEpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,WAAW,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAItD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAgBrD;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,gBAAgB,KAAK,IAAI,GAAE,iBAAiB,CAE3F;AACD,wBAAgB,YAAY,CAAC,QAAQ,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,GAAE,iBAAiB,CAErF;AAED,OAAO,EACL,WAAW,EACX,QAAQ,EACR,eAAe,EACf,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,WAAW,GACZ,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { Environment } from '../NativeReactAmwalPay';
2
+ declare class NetworkClient {
3
+ private static instance;
4
+ private constructor();
5
+ static getInstance(): NetworkClient;
6
+ private getWebhookUrl;
7
+ fetchSessionToken(env: Environment, merchantId: string, customerId: string | null, secureHashValue: string): Promise<string | null>;
8
+ private showErrorDialog;
9
+ }
10
+ export default NetworkClient;
11
+ //# sourceMappingURL=NetworkClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NetworkClient.d.ts","sourceRoot":"","sources":["../../../../src/network/NetworkClient.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAGrD,cAAM,aAAa;IACjB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAgB;IAEvC,OAAO;IAEP,MAAM,CAAC,WAAW,IAAI,aAAa;IAOnC,OAAO,CAAC,aAAa;IAaf,iBAAiB,CACrB,GAAG,EAAE,WAAW,EAChB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAwCzB,OAAO,CAAC,eAAe;CAOxB;AAED,eAAe,aAAa,CAAC"}
@@ -0,0 +1,10 @@
1
+ type DataMap = {
2
+ [key: string]: string | null;
3
+ };
4
+ declare class SecureHashUtil {
5
+ static clearSecureHash(secretKey: string, data: DataMap): string;
6
+ private static composeData;
7
+ private static generateSecureHash;
8
+ }
9
+ export default SecureHashUtil;
10
+ //# sourceMappingURL=SecureHashUtil.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SecureHashUtil.d.ts","sourceRoot":"","sources":["../../../../src/utils/SecureHashUtil.ts"],"names":[],"mappings":"AAGA,KAAK,OAAO,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAEhD,cAAM,cAAc;IAClB,MAAM,CAAC,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM;IAMhE,OAAO,CAAC,MAAM,CAAC,WAAW;IAQ1B,OAAO,CAAC,MAAM,CAAC,kBAAkB;CAsBlC;AAED,eAAe,cAAc,CAAC"}
package/package.json ADDED
@@ -0,0 +1,167 @@
1
+ {
2
+ "name": "react-amwal-pay",
3
+ "version": "0.1.0",
4
+ "description": "amwal pay",
5
+ "main": "./lib/module/index.js",
6
+ "types": "./lib/typescript/src/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "source": "./src/index.tsx",
10
+ "types": "./lib/typescript/src/index.d.ts",
11
+ "default": "./lib/module/index.js"
12
+ },
13
+ "./package.json": "./package.json"
14
+ },
15
+ "files": [
16
+ "src",
17
+ "lib",
18
+ "android",
19
+ "ios",
20
+ "cpp",
21
+ "*.podspec",
22
+ "react-native.config.js",
23
+ "!ios/build",
24
+ "!android/build",
25
+ "!android/gradle",
26
+ "!android/gradlew",
27
+ "!android/gradlew.bat",
28
+ "!android/local.properties",
29
+ "!**/__tests__",
30
+ "!**/__fixtures__",
31
+ "!**/__mocks__",
32
+ "!**/.*"
33
+ ],
34
+ "scripts": {
35
+ "example": "yarn workspace react-amwal-pay-example",
36
+ "test": "jest",
37
+ "typecheck": "tsc",
38
+ "lint": "eslint \"**/*.{js,ts,tsx}\"",
39
+ "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
40
+ "prepare": "bob build",
41
+ "release": "release-it --only-version"
42
+ },
43
+ "keywords": [
44
+ "react-native",
45
+ "ios",
46
+ "android"
47
+ ],
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "git+https://https://github.com/amwal-pay/AnwalPaySDKReactNative.git"
51
+ },
52
+ "author": "amr saied <amr.elskaan@amwal-pay.com> (https://)",
53
+ "license": "MIT",
54
+ "bugs": {
55
+ "url": "https:///issues"
56
+ },
57
+ "homepage": "https://#readme",
58
+ "publishConfig": {
59
+ "registry": "https://registry.npmjs.org/"
60
+ },
61
+ "devDependencies": {
62
+ "@commitlint/config-conventional": "^19.6.0",
63
+ "@eslint/compat": "^1.2.7",
64
+ "@eslint/eslintrc": "^3.3.0",
65
+ "@eslint/js": "^9.22.0",
66
+ "@evilmartians/lefthook": "^1.5.0",
67
+ "@react-native-community/cli": "15.0.0-alpha.2",
68
+ "@react-native/babel-preset": "0.79.2",
69
+ "@react-native/eslint-config": "^0.78.0",
70
+ "@release-it/conventional-changelog": "^9.0.2",
71
+ "@types/crypto-js": "^4.2.2",
72
+ "@types/jest": "^29.5.5",
73
+ "@types/react": "^19.0.0",
74
+ "commitlint": "^19.6.1",
75
+ "del-cli": "^5.1.0",
76
+ "eslint": "^9.22.0",
77
+ "eslint-config-prettier": "^10.1.1",
78
+ "eslint-plugin-prettier": "^5.2.3",
79
+ "jest": "^29.7.0",
80
+ "prettier": "^3.0.3",
81
+ "react": "19.0.0",
82
+ "react-native": "0.79.2",
83
+ "react-native-builder-bob": "^0.40.11",
84
+ "release-it": "^17.10.0",
85
+ "turbo": "^1.10.7",
86
+ "typescript": "^5.8.3"
87
+ },
88
+ "peerDependencies": {
89
+ "react": "*",
90
+ "react-native": "*"
91
+ },
92
+ "workspaces": [
93
+ "example"
94
+ ],
95
+ "packageManager": "yarn@3.6.1",
96
+ "jest": {
97
+ "preset": "react-native",
98
+ "modulePathIgnorePatterns": [
99
+ "<rootDir>/example/node_modules",
100
+ "<rootDir>/lib/"
101
+ ]
102
+ },
103
+ "commitlint": {
104
+ "extends": [
105
+ "@commitlint/config-conventional"
106
+ ]
107
+ },
108
+ "release-it": {
109
+ "git": {
110
+ "commitMessage": "chore: release ${version}",
111
+ "tagName": "v${version}"
112
+ },
113
+ "npm": {
114
+ "publish": true
115
+ },
116
+ "github": {
117
+ "release": true
118
+ },
119
+ "plugins": {
120
+ "@release-it/conventional-changelog": {
121
+ "preset": {
122
+ "name": "angular"
123
+ }
124
+ }
125
+ }
126
+ },
127
+ "prettier": {
128
+ "quoteProps": "consistent",
129
+ "singleQuote": true,
130
+ "tabWidth": 2,
131
+ "trailingComma": "es5",
132
+ "useTabs": false
133
+ },
134
+ "react-native-builder-bob": {
135
+ "source": "src",
136
+ "output": "lib",
137
+ "targets": [
138
+ [
139
+ "module",
140
+ {
141
+ "esm": true
142
+ }
143
+ ],
144
+ [
145
+ "typescript",
146
+ {
147
+ "project": "tsconfig.build.json"
148
+ }
149
+ ]
150
+ ]
151
+ },
152
+ "codegenConfig": {
153
+ "name": "ReactAmwalPaySpec",
154
+ "type": "modules",
155
+ "jsSrcsDir": "src",
156
+ "android": {
157
+ "javaPackageName": "com.reactamwalpay"
158
+ }
159
+ },
160
+ "create-react-native-library": {
161
+ "languages": "kotlin-objc",
162
+ "type": "turbo-module",
163
+ "version": "0.50.3"
164
+ },
165
+ "dependencies": {
166
+ }
167
+ }
@@ -0,0 +1,98 @@
1
+ import { initiate, onCustomerId, onResponse, type AmwalPayConfig } from './index';
2
+ import NetworkClient from './network/NetworkClient';
3
+ import { type EventSubscription } from 'react-native';
4
+
5
+
6
+ class AmwalPaySDK {
7
+ private static instance: AmwalPaySDK;
8
+
9
+ private onResponseSubscription: EventSubscription|null = null;
10
+
11
+ private onCustomerIdSubscription: EventSubscription|null = null;
12
+
13
+ private constructor() {
14
+ // Initialize the event emitter
15
+
16
+ }
17
+
18
+ static getInstance(): AmwalPaySDK {
19
+ if (!AmwalPaySDK.instance) {
20
+ AmwalPaySDK.instance = new AmwalPaySDK();
21
+ }
22
+ return AmwalPaySDK.instance;
23
+ }
24
+
25
+ /**
26
+ * Initiates the payment process by first fetching a session token and then starting the payment flow
27
+ * @param config The payment configuration
28
+ */
29
+ async startPayment(config: Omit<AmwalPayConfig, 'sessionToken'>): Promise<void> {
30
+ try {
31
+ // Set up event listeners before starting the payment process
32
+ this.setupEventListeners(config);
33
+
34
+ // Get network client instance
35
+ const networkClient = NetworkClient.getInstance();
36
+
37
+ // Fetch session token
38
+ const sessionToken = await networkClient.fetchSessionToken(
39
+ config.environment,
40
+ config.merchantId,
41
+ config.customerId,
42
+ config.secureHash
43
+ );
44
+
45
+ if (!sessionToken) {
46
+ // If session token is null, the error has already been shown by NetworkClient
47
+ return;
48
+ }
49
+
50
+ // Create complete config with session token
51
+ const completeConfig: AmwalPayConfig = {
52
+ ...config,
53
+ sessionToken
54
+ };
55
+
56
+ // Initiate the payment process
57
+ initiate(completeConfig);
58
+ } catch (error) {
59
+ console.error('Error starting payment:', error);
60
+ }
61
+ }
62
+
63
+ dispose(): void {
64
+ // Remove all event listeners
65
+ this.removeEventListeners();
66
+ }
67
+
68
+ /**
69
+ * Sets up event listeners for AmwalPay events
70
+ * @param config The payment configuration containing callback functions
71
+ */
72
+ private setupEventListeners(config: Omit<AmwalPayConfig, 'sessionToken'>): void {
73
+ // Remove any existing listeners
74
+ this.removeEventListeners();
75
+
76
+ this.onResponseSubscription = onResponse((response) => {
77
+ console.log('Received AmwalPayResponse:', response);
78
+ config.onResponse(response);
79
+ });
80
+
81
+ this.onCustomerIdSubscription = onCustomerId((customerId) => {
82
+ console.log('Received customerId:', customerId);
83
+ config.onCustomerId(customerId);
84
+ });
85
+ }
86
+
87
+ /**
88
+ * Removes all event listeners
89
+ */
90
+ private removeEventListeners(): void {
91
+ this.onResponseSubscription?.remove();
92
+ this.onCustomerIdSubscription?.remove();
93
+ this.onResponseSubscription = null;
94
+ this.onCustomerIdSubscription = null;
95
+ }
96
+ }
97
+
98
+ export default AmwalPaySDK;
@@ -0,0 +1,64 @@
1
+ import type { TurboModule } from 'react-native';
2
+ import { TurboModuleRegistry } from 'react-native';
3
+ import type { EventEmitter } from 'react-native/Libraries/Types/CodegenTypes';
4
+
5
+ export enum Environment {
6
+ SIT = 'SIT',
7
+ UAT = 'UAT',
8
+ PROD = 'PROD'
9
+ }
10
+
11
+ export enum Currency {
12
+ OMR = 'OMR',
13
+ }
14
+
15
+ export enum TransactionType {
16
+ NFC= 'NFC' ,
17
+ CARD_WALLET= 'CARD_WALLET',
18
+ APPLE_PAY= 'APPLE_PAY'
19
+ }
20
+
21
+ export interface AmwalPayResponse {
22
+ status: string;
23
+ message: string;
24
+ data?: Object; // Changed from 'any' to 'Object'
25
+ }
26
+
27
+ // This interface is for JavaScript side only, not for the native module spec
28
+ export interface AmwalPayConfig {
29
+ environment: Environment;
30
+ secureHash: string;
31
+ currency: Currency;
32
+ amount: string;
33
+ merchantId: string;
34
+ terminalId: string;
35
+ locale: string;
36
+ customerId: string | null;
37
+ transactionType: TransactionType;
38
+ sessionToken?: string;
39
+ onResponse: (response: AmwalPayResponse) => void;
40
+ onCustomerId: (customerId: string) => void;
41
+ }
42
+
43
+ // This is the configuration that will be passed to the native module
44
+ export interface AmwalPayNativeConfig {
45
+ environment: string;
46
+ secureHash: string;
47
+ currency: string;
48
+ amount: string;
49
+ merchantId: string;
50
+ terminalId: string;
51
+ locale: string;
52
+ customerId: string | null;
53
+ transactionType: string;
54
+ sessionToken?: string;
55
+ }
56
+
57
+ export interface Spec extends TurboModule {
58
+ // Change the parameter type to AmwalPayNativeConfig
59
+ initiate(config: AmwalPayNativeConfig): void;
60
+ onResponse: EventEmitter<AmwalPayResponse>,
61
+ onCustomerId: EventEmitter<string>,
62
+ }
63
+
64
+ export default TurboModuleRegistry.getEnforcing<Spec>('ReactAmwalPay');
package/src/index.tsx ADDED
@@ -0,0 +1,46 @@
1
+ import ReactAmwalPay, {
2
+ Environment,
3
+ Currency,
4
+ TransactionType,
5
+ type AmwalPayResponse,
6
+ type AmwalPayConfig,
7
+ type AmwalPayNativeConfig,
8
+ } from './NativeReactAmwalPay';
9
+ import AmwalPaySDK from './AmwalPaySDK';
10
+ import type { EventSubscription } from 'react-native';
11
+
12
+ // Create an event emitter for the native module
13
+
14
+ export function initiate(config: AmwalPayConfig): void {
15
+ const nativeConfig: AmwalPayNativeConfig = {
16
+ environment: config.environment,
17
+ secureHash: config.secureHash,
18
+ currency: config.currency,
19
+ amount: config.amount,
20
+ merchantId: config.merchantId,
21
+ terminalId: config.terminalId,
22
+ locale: config.locale,
23
+ customerId: config.customerId,
24
+ transactionType: config.transactionType,
25
+ sessionToken: config.sessionToken,
26
+ };
27
+
28
+ // Call the native module
29
+ ReactAmwalPay.initiate(nativeConfig);
30
+ }
31
+
32
+ export function onResponse(callback: (response: AmwalPayResponse) => void):EventSubscription {
33
+ return ReactAmwalPay.onResponse(callback);
34
+ }
35
+ export function onCustomerId(callback: (customerId: string) => void):EventSubscription {
36
+ return ReactAmwalPay.onCustomerId(callback);
37
+ }
38
+
39
+ export {
40
+ Environment,
41
+ Currency,
42
+ TransactionType,
43
+ type AmwalPayResponse,
44
+ type AmwalPayConfig,
45
+ AmwalPaySDK,
46
+ };
@@ -0,0 +1,84 @@
1
+ import { Alert } from 'react-native';
2
+ import { Environment } from '../NativeReactAmwalPay';
3
+ import SecureHashUtil from '../utils/SecureHashUtil';
4
+
5
+ class NetworkClient {
6
+ private static instance: NetworkClient;
7
+
8
+ private constructor() {}
9
+
10
+ static getInstance(): NetworkClient {
11
+ if (!NetworkClient.instance) {
12
+ NetworkClient.instance = new NetworkClient();
13
+ }
14
+ return NetworkClient.instance;
15
+ }
16
+
17
+ private getWebhookUrl(env: Environment): string {
18
+ switch (env) {
19
+ case Environment.SIT:
20
+ return 'https://test.amwalpg.com:24443/';
21
+ case Environment.UAT:
22
+ return 'https://test.amwalpg.com:14443/';
23
+ case Environment.PROD:
24
+ return 'https://webhook.amwalpg.com/';
25
+ default:
26
+ return 'https://test.amwalpg.com:24443/';
27
+ }
28
+ }
29
+
30
+ async fetchSessionToken(
31
+ env: Environment,
32
+ merchantId: string,
33
+ customerId: string | null,
34
+ secureHashValue: string
35
+ ): Promise<string | null> {
36
+ try {
37
+ const webhookUrl = this.getWebhookUrl(env);
38
+
39
+ const dataMap = {
40
+ merchantId,
41
+ customerId
42
+ };
43
+
44
+ const secureHash = SecureHashUtil.clearSecureHash(secureHashValue, dataMap);
45
+
46
+ const response = await fetch(`${webhookUrl}Membership/GetSDKSessionToken`, {
47
+ method: 'POST',
48
+ headers: {
49
+ 'Accept': 'text/plain',
50
+ 'Accept-Language': 'en-US,en;q=0.9',
51
+ 'Content-Type': 'application/json',
52
+ },
53
+ body: JSON.stringify({
54
+ merchantId,
55
+ secureHashValue: secureHash,
56
+ customerId
57
+ })
58
+ });
59
+
60
+ const responseData = await response.json();
61
+
62
+ if (response.ok && responseData.success) {
63
+ return responseData.data.sessionToken;
64
+ } else {
65
+ const errorMessage = responseData.errorList?.join(',') || 'Unknown error';
66
+ this.showErrorDialog(errorMessage);
67
+ return null;
68
+ }
69
+ } catch (error) {
70
+ this.showErrorDialog('Something Went Wrong');
71
+ return null;
72
+ }
73
+ }
74
+
75
+ private showErrorDialog(message: string): void {
76
+ Alert.alert(
77
+ 'Error',
78
+ message,
79
+ [{ text: 'OK' }]
80
+ );
81
+ }
82
+ }
83
+
84
+ export default NetworkClient;
@@ -0,0 +1,45 @@
1
+ import HmacSHA256 from 'crypto-js/hmac-sha256';
2
+ import Hex from 'crypto-js/enc-hex';
3
+
4
+ type DataMap = { [key: string]: string | null };
5
+
6
+ class SecureHashUtil {
7
+ static clearSecureHash(secretKey: string, data: DataMap): string {
8
+ delete data.secureHashValue;
9
+ const concatenatedString = this.composeData(data);
10
+ return this.generateSecureHash(concatenatedString, secretKey);
11
+ }
12
+
13
+ private static composeData(requestParameters: DataMap): string {
14
+ return Object.entries(requestParameters)
15
+ .sort(([keyA], [keyB]) => keyA.localeCompare(keyB))
16
+ .filter(([_, value]) => value != null && value !== '')
17
+ .map(([key, value]) => `${key}=${value}`)
18
+ .join('&');
19
+ }
20
+
21
+ private static generateSecureHash(message: string, secretKey: string): string {
22
+ try {
23
+ // Convert hex string to byte array
24
+ const keyBytes = secretKey.match(/.{2}/g)?.map(byte => parseInt(byte, 16));
25
+
26
+ if (!keyBytes) {
27
+ throw new Error('Invalid secret key format');
28
+ }
29
+
30
+ // Convert key bytes to hex string for crypto-js
31
+ const keyHex = keyBytes.map(byte => byte.toString(16).padStart(2, '0')).join('');
32
+
33
+ // Generate HMAC-SHA256
34
+ const hash = HmacSHA256(message, Hex.parse(keyHex));
35
+
36
+ // Convert to uppercase hex string
37
+ return hash.toString(Hex).toUpperCase();
38
+ } catch (e) {
39
+ console.error('Error generating secure hash:', e);
40
+ return '';
41
+ }
42
+ }
43
+ }
44
+
45
+ export default SecureHashUtil;