react-amwal-pay 0.1.1 → 0.1.2

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.
@@ -1,98 +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
-
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
98
  export default AmwalPaySDK;
@@ -1,84 +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
-
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
84
  export default NetworkClient;
@@ -1,45 +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
-
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
45
  export default SecureHashUtil;
@@ -1,95 +0,0 @@
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
- }
@@ -1,5 +0,0 @@
1
- ReactAmwalPay_kotlinVersion=2.0.0
2
- ReactAmwalPay_minSdkVersion=24
3
- ReactAmwalPay_targetSdkVersion=34
4
- ReactAmwalPay_compileSdkVersion=35
5
- ReactAmwalPay_ndkVersion=27.1.12297006
@@ -1,2 +0,0 @@
1
- <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
- </manifest>
@@ -1,115 +0,0 @@
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
- }