react-native-pfm-sdk-react-native 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.
- package/LICENSE +20 -0
- package/PfmSdkReactNative.podspec +24 -0
- package/README.md +37 -0
- package/android/build.gradle +83 -0
- package/android/src/main/AndroidManifest.xml +10 -0
- package/android/src/main/java/com/pfmsdkreactnative/LuneActivity.kt +50 -0
- package/android/src/main/java/com/pfmsdkreactnative/PfmSdkReactNativeModule.kt +99 -0
- package/android/src/main/java/com/pfmsdkreactnative/PfmSdkReactNativePackage.kt +31 -0
- package/ios/LuneSelectorView.swift +48 -0
- package/ios/PfmSdkReactNative.h +22 -0
- package/ios/PfmSdkReactNative.mm +90 -0
- package/ios/PfmSdkReactNative.swift +130 -0
- package/lib/module/NativePfmSdkReactNative.js +24 -0
- package/lib/module/NativePfmSdkReactNative.js.map +1 -0
- package/lib/module/index.js +66 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativePfmSdkReactNative.d.ts +29 -0
- package/lib/typescript/src/NativePfmSdkReactNative.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +19 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/package.json +175 -0
- package/src/NativePfmSdkReactNative.ts +37 -0
- package/src/index.tsx +92 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Eslam Ali
|
|
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.
|
|
@@ -0,0 +1,24 @@
|
|
|
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 = "PfmSdkReactNative"
|
|
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
|
+
s.swift_version = "5.0"
|
|
13
|
+
|
|
14
|
+
s.platforms = { :ios => "13.0" }
|
|
15
|
+
|
|
16
|
+
s.source = { :git => "https://github.com/eslam-ali-ios-lune/react-native-pfm-sdk-react-native.git", :tag => "#{s.version}" }
|
|
17
|
+
|
|
18
|
+
s.source_files = "ios/**/*.{h,m,mm,swift,cpp}"
|
|
19
|
+
s.private_header_files = "ios/**/*.h"
|
|
20
|
+
|
|
21
|
+
install_modules_dependencies(s)
|
|
22
|
+
|
|
23
|
+
s.dependency "LuneSDK", "0.7.4"
|
|
24
|
+
end
|
package/README.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# react-native-pfm-sdk-react-native
|
|
2
|
+
|
|
3
|
+
React native plugin that intergates with native iOS and Android SDKs
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
npm install react-native-pfm-sdk-react-native
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
import { multiply } from 'react-native-pfm-sdk-react-native';
|
|
18
|
+
|
|
19
|
+
// ...
|
|
20
|
+
|
|
21
|
+
const result = multiply(3, 7);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
## Contributing
|
|
26
|
+
|
|
27
|
+
- [Development workflow](CONTRIBUTING.md#development-workflow)
|
|
28
|
+
- [Sending a pull request](CONTRIBUTING.md#sending-a-pull-request)
|
|
29
|
+
- [Code of conduct](CODE_OF_CONDUCT.md)
|
|
30
|
+
|
|
31
|
+
## License
|
|
32
|
+
|
|
33
|
+
MIT
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
buildscript {
|
|
2
|
+
ext.PfmSdkReactNative = [
|
|
3
|
+
kotlinVersion: "2.0.21",
|
|
4
|
+
minSdkVersion: 24,
|
|
5
|
+
compileSdkVersion: 36,
|
|
6
|
+
targetSdkVersion: 36
|
|
7
|
+
]
|
|
8
|
+
|
|
9
|
+
ext.getExtOrDefault = { prop ->
|
|
10
|
+
if (rootProject.ext.has(prop)) {
|
|
11
|
+
return rootProject.ext.get(prop)
|
|
12
|
+
}
|
|
13
|
+
return PfmSdkReactNative[prop]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
repositories {
|
|
17
|
+
google()
|
|
18
|
+
mavenCentral()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
dependencies {
|
|
22
|
+
classpath "com.android.tools.build:gradle:8.7.2"
|
|
23
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
|
|
24
|
+
// 🚀 Correct: This is a build tool plugin
|
|
25
|
+
classpath "org.jetbrains.kotlin:compose-compiler-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
apply plugin: "com.android.library"
|
|
30
|
+
apply plugin: "kotlin-android"
|
|
31
|
+
apply plugin: "com.facebook.react"
|
|
32
|
+
apply plugin: "org.jetbrains.kotlin.plugin.compose"
|
|
33
|
+
|
|
34
|
+
android {
|
|
35
|
+
namespace "com.pfmsdkreactnative"
|
|
36
|
+
compileSdkVersion getExtOrDefault("compileSdkVersion")
|
|
37
|
+
|
|
38
|
+
defaultConfig {
|
|
39
|
+
minSdkVersion getExtOrDefault("minSdkVersion")
|
|
40
|
+
targetSdkVersion getExtOrDefault("targetSdkVersion")
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
buildFeatures {
|
|
44
|
+
buildConfig true
|
|
45
|
+
compose true
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
buildTypes {
|
|
49
|
+
release {
|
|
50
|
+
minifyEnabled false
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
lint {
|
|
55
|
+
disable "GradleCompatible"
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
compileOptions {
|
|
59
|
+
sourceCompatibility JavaVersion.VERSION_17
|
|
60
|
+
targetCompatibility JavaVersion.VERSION_17
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
kotlinOptions {
|
|
64
|
+
jvmTarget = "17"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
dependencies {
|
|
69
|
+
implementation "com.facebook.react:react-android"
|
|
70
|
+
|
|
71
|
+
// 🚀 1. Lune SDK
|
|
72
|
+
implementation("io.lunedata.lunesdk:lunesdk:0.3.14")
|
|
73
|
+
|
|
74
|
+
// 🚀 2. Compose BOM & Core UI
|
|
75
|
+
def composeBom = platform('androidx.compose:compose-bom:2024.02.00')
|
|
76
|
+
implementation composeBom
|
|
77
|
+
implementation 'androidx.compose.ui:ui'
|
|
78
|
+
implementation 'androidx.compose.material3:material3' // Moved from buildscript to here
|
|
79
|
+
implementation 'androidx.compose.foundation:foundation'
|
|
80
|
+
|
|
81
|
+
// 🚀 3. Required for Activity-based rendering
|
|
82
|
+
implementation 'androidx.activity:activity-compose:1.8.2'
|
|
83
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
2
|
+
package="com.pfmsdkreactnative">
|
|
3
|
+
|
|
4
|
+
<uses-permission android:name="android.permission.INTERNET" />
|
|
5
|
+
|
|
6
|
+
<application>
|
|
7
|
+
<activity android:name=".LuneActivity" />
|
|
8
|
+
</application>
|
|
9
|
+
|
|
10
|
+
</manifest>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
package com.pfmsdkreactnative
|
|
2
|
+
|
|
3
|
+
import android.os.Bundle
|
|
4
|
+
import androidx.activity.ComponentActivity
|
|
5
|
+
import androidx.activity.compose.setContent
|
|
6
|
+
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
7
|
+
import androidx.compose.material3.ModalBottomSheet
|
|
8
|
+
import androidx.compose.material3.rememberModalBottomSheetState
|
|
9
|
+
import androidx.compose.ui.graphics.Color
|
|
10
|
+
import androidx.compose.material3.MaterialTheme
|
|
11
|
+
|
|
12
|
+
// 🚀 FIXED IMPORT from your Cordova snippet
|
|
13
|
+
import io.lunedata.lunesdk.library.classes.LuneSDKManager
|
|
14
|
+
|
|
15
|
+
class LuneActivity : ComponentActivity() {
|
|
16
|
+
@OptIn(ExperimentalMaterial3Api::class)
|
|
17
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
18
|
+
super.onCreate(savedInstanceState)
|
|
19
|
+
|
|
20
|
+
val rawUrl = intent.getStringExtra("baseUrl") ?: ""
|
|
21
|
+
val baseUrl = if (rawUrl.endsWith("/")) rawUrl else "$rawUrl/"
|
|
22
|
+
val token = intent.getStringExtra("token") ?: ""
|
|
23
|
+
val viewType = intent.getStringExtra("viewType") ?: ""
|
|
24
|
+
|
|
25
|
+
// 🚀 Initialize SDK with the static refresher from your Module
|
|
26
|
+
val sdk = LuneSDKManager(
|
|
27
|
+
baseUrl = baseUrl,
|
|
28
|
+
token = token,
|
|
29
|
+
refreshTokenCallback = PfmSdkReactNativeModule.tokenRefresher
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
setContent {
|
|
33
|
+
MaterialTheme {
|
|
34
|
+
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
|
35
|
+
ModalBottomSheet(
|
|
36
|
+
onDismissRequest = { finish() },
|
|
37
|
+
sheetState = sheetState,
|
|
38
|
+
containerColor = Color.White
|
|
39
|
+
) {
|
|
40
|
+
when (viewType) {
|
|
41
|
+
"cashflow" -> sdk.CashflowComponent()
|
|
42
|
+
"budget" -> sdk.BudgetComponent()
|
|
43
|
+
"spend" -> sdk.ExpenseComponent()
|
|
44
|
+
else -> sdk.ExpenseComponent()
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
package com.pfmsdkreactnative
|
|
2
|
+
|
|
3
|
+
import android.content.Intent
|
|
4
|
+
import android.util.Log
|
|
5
|
+
import com.facebook.react.bridge.Promise
|
|
6
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
7
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
8
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
9
|
+
import io.lunedata.lunesdk.library.classes.RefreshTokenCallback // 🚀 Import Refresher
|
|
10
|
+
import java.util.concurrent.CountDownLatch
|
|
11
|
+
|
|
12
|
+
@ReactModule(name = PfmSdkReactNativeModule.NAME)
|
|
13
|
+
class PfmSdkReactNativeModule(private val reactContext: ReactApplicationContext) :
|
|
14
|
+
NativePfmSdkReactNativeSpec(reactContext) {
|
|
15
|
+
|
|
16
|
+
companion object {
|
|
17
|
+
const val NAME = "PfmSdkReactNative"
|
|
18
|
+
var savedBaseUrl: String = ""
|
|
19
|
+
var savedToken: String = ""
|
|
20
|
+
|
|
21
|
+
// 🚦 Latch logic for Token Refresh
|
|
22
|
+
var tokenLatch: CountDownLatch? = null
|
|
23
|
+
var newTokenResponse: String? = null
|
|
24
|
+
|
|
25
|
+
val tokenRefresher = object : RefreshTokenCallback {
|
|
26
|
+
override fun refreshToken(): String? {
|
|
27
|
+
tokenLatch = CountDownLatch(1)
|
|
28
|
+
newTokenResponse = null
|
|
29
|
+
|
|
30
|
+
// 📢 Notify React Native that we need a token
|
|
31
|
+
// This maps to the 'onRefreshToken' listener in JS
|
|
32
|
+
instance?.sendEvent("onRefreshToken", null)
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
tokenLatch?.await() // 🚦 Pause thread until JS calls submitNewToken
|
|
36
|
+
} catch (e: InterruptedException) {
|
|
37
|
+
Log.e("LuneSDK", "Token wait interrupted", e)
|
|
38
|
+
}
|
|
39
|
+
return newTokenResponse
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private var instance: PfmSdkReactNativeModule? = null
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
init { instance = this }
|
|
47
|
+
|
|
48
|
+
override fun getName() = NAME
|
|
49
|
+
|
|
50
|
+
override fun initializeSdk(baseUrl: String, accessToken: String, promise: Promise) {
|
|
51
|
+
savedBaseUrl = baseUrl
|
|
52
|
+
savedToken = accessToken
|
|
53
|
+
promise.resolve(null)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 🚀 Call this from JS when you have the new token
|
|
57
|
+
override fun registerRefreshTokenCallback(promise: Promise) {
|
|
58
|
+
// In TurboModules, we use this to signify JS is ready to listen
|
|
59
|
+
promise.resolve(null)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Use this to pass the token back from JS
|
|
63
|
+
fun submitNewToken(token: String?) {
|
|
64
|
+
newTokenResponse = token
|
|
65
|
+
if (token != null) savedToken = token
|
|
66
|
+
tokenLatch?.countDown() // 🟢 Resume the SDK thread
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
override fun showLuneView(viewIdentifier: String, promise: Promise) {
|
|
70
|
+
val currentActivity = reactContext.currentActivity
|
|
71
|
+
if (currentActivity == null) {
|
|
72
|
+
promise.reject("ERROR", "No Activity")
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
val intent = Intent(currentActivity, LuneActivity::class.java).apply {
|
|
77
|
+
putExtra("viewType", viewIdentifier)
|
|
78
|
+
putExtra("baseUrl", savedBaseUrl)
|
|
79
|
+
putExtra("token", savedToken)
|
|
80
|
+
}
|
|
81
|
+
currentActivity.startActivity(intent)
|
|
82
|
+
promise.resolve(null)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private fun sendEvent(eventName: String, params: String?) {
|
|
86
|
+
reactContext
|
|
87
|
+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
88
|
+
.emit(eventName, params)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Boilerplate for other methods...
|
|
92
|
+
override fun optInForEventListener(promise: Promise) { promise.resolve(null) }
|
|
93
|
+
override fun optInForErrorLogger(promise: Promise) { promise.resolve(null) }
|
|
94
|
+
override fun optInForErrorNotifier(promise: Promise) { promise.resolve(null) }
|
|
95
|
+
override fun optInForSuccessNotifier(promise: Promise) { promise.resolve(null) }
|
|
96
|
+
override fun destroySdk(promise: Promise) { promise.resolve(null) }
|
|
97
|
+
override fun addListener(eventName: String) {}
|
|
98
|
+
override fun removeListeners(count: Double) {}
|
|
99
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
package com.pfmsdkreactnative
|
|
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 PfmSdkReactNativePackage : BaseReactPackage() {
|
|
11
|
+
override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
|
|
12
|
+
return if (name == PfmSdkReactNativeModule.NAME) {
|
|
13
|
+
PfmSdkReactNativeModule(reactContext)
|
|
14
|
+
} else {
|
|
15
|
+
null
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
override fun getReactModuleInfoProvider() = ReactModuleInfoProvider {
|
|
20
|
+
mapOf(
|
|
21
|
+
PfmSdkReactNativeModule.NAME to ReactModuleInfo(
|
|
22
|
+
name = PfmSdkReactNativeModule.NAME,
|
|
23
|
+
className = PfmSdkReactNativeModule.NAME,
|
|
24
|
+
canOverrideExistingModule = false,
|
|
25
|
+
needsEagerInit = false,
|
|
26
|
+
isCxxModule = false,
|
|
27
|
+
isTurboModule = true
|
|
28
|
+
)
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
import LuneSDK
|
|
3
|
+
|
|
4
|
+
public struct LuneSelectorView: View {
|
|
5
|
+
public let viewType: String
|
|
6
|
+
public let baseUrl: String
|
|
7
|
+
public let token: String
|
|
8
|
+
|
|
9
|
+
// Initialize the manager using the props passed from React Native
|
|
10
|
+
var sdkManager: LuneSDKManager {
|
|
11
|
+
LuneSDKManager(baseUrl: baseUrl, token: token)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public init(viewType: String, baseUrl: String, token: String) {
|
|
15
|
+
self.viewType = viewType
|
|
16
|
+
self.baseUrl = baseUrl
|
|
17
|
+
self.token = token
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// @ViewBuilder is required when a switch statement returns different view types
|
|
21
|
+
@ViewBuilder
|
|
22
|
+
public var body: some View {
|
|
23
|
+
switch viewType {
|
|
24
|
+
case "cashflow":
|
|
25
|
+
sdkManager.CashflowComponent()
|
|
26
|
+
case "spend":
|
|
27
|
+
sdkManager.ExpenseComponent()
|
|
28
|
+
case "budget":
|
|
29
|
+
sdkManager.BudgetComponent()
|
|
30
|
+
case "category_spend_chart":
|
|
31
|
+
sdkManager.CategorySpendChartComponent()
|
|
32
|
+
case "cashflow_chart":
|
|
33
|
+
sdkManager.CashflowChartComponent()
|
|
34
|
+
case "brand_trend_chart":
|
|
35
|
+
sdkManager.BrandTrendChartComponent()
|
|
36
|
+
case "category_trend_chart":
|
|
37
|
+
sdkManager.CategoryTrendChartComponent()
|
|
38
|
+
case "transaction_list":
|
|
39
|
+
sdkManager.TransactionListComponent()
|
|
40
|
+
case "brand_trend":
|
|
41
|
+
sdkManager.BrandTrendsComponent()
|
|
42
|
+
case "category_trend":
|
|
43
|
+
sdkManager.CategoryTrendsComponent()
|
|
44
|
+
default:
|
|
45
|
+
Text("Unknown View Type: \(viewType)")
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#import <React/RCTBridgeModule.h>
|
|
2
|
+
#import <React/RCTEventEmitter.h>
|
|
3
|
+
|
|
4
|
+
// If you are using the New Architecture, we include the spec
|
|
5
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
6
|
+
#import "RNPfmSdkReactNativeSpec.h"
|
|
7
|
+
#endif
|
|
8
|
+
|
|
9
|
+
// We define the interface. Note that it ALWAYS inherits from RCTEventEmitter
|
|
10
|
+
@interface PfmSdkReactNative : RCTEventEmitter <
|
|
11
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
12
|
+
NativePfmSdkReactNativeSpec
|
|
13
|
+
#else
|
|
14
|
+
RCTBridgeModule
|
|
15
|
+
#endif
|
|
16
|
+
>
|
|
17
|
+
|
|
18
|
+
// This declaration is the most important part.
|
|
19
|
+
// It tells the .mm file that this method exists in the parent class.
|
|
20
|
+
- (void)sendEventWithName:(NSString *)name body:(id)body;
|
|
21
|
+
|
|
22
|
+
@end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#import "PfmSdkReactNative.h"
|
|
2
|
+
|
|
3
|
+
// This magic line imports your Swift code into Objective-C
|
|
4
|
+
#if __has_include("PfmSdkReactNative-Swift.h")
|
|
5
|
+
#import "PfmSdkReactNative-Swift.h"
|
|
6
|
+
#else
|
|
7
|
+
#import <PfmSdkReactNative/PfmSdkReactNative-Swift.h>
|
|
8
|
+
#endif
|
|
9
|
+
|
|
10
|
+
@implementation PfmSdkReactNative
|
|
11
|
+
|
|
12
|
+
RCT_EXPORT_MODULE()
|
|
13
|
+
|
|
14
|
+
// --- TURBOMODULE METHOD ---
|
|
15
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
16
|
+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
17
|
+
(const facebook::react::ObjCTurboModule::InitParams &)params
|
|
18
|
+
{
|
|
19
|
+
return std::make_shared<facebook::react::NativePfmSdkReactNativeSpecJSI>(params);
|
|
20
|
+
}
|
|
21
|
+
#endif
|
|
22
|
+
// ----------------------------------------
|
|
23
|
+
|
|
24
|
+
// 1. Declare the events JavaScript is allowed to listen to
|
|
25
|
+
- (NSArray<NSString *> *)supportedEvents {
|
|
26
|
+
return @[@"onLuneEvent", @"onLuneError", @"onLuneSuccess", @"onLuneTokenRefresh"];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 2. Initialize the SDK
|
|
30
|
+
RCT_EXPORT_METHOD(initializeSdk:(NSString *)baseUrl
|
|
31
|
+
accessToken:(NSString *)accessToken
|
|
32
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
33
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
34
|
+
{
|
|
35
|
+
PfmSdkReactNativeImpl *sharedImpl = [PfmSdkReactNativeImpl shared];
|
|
36
|
+
|
|
37
|
+
sharedImpl.sendEvent = ^(NSString *eventName, id body) {
|
|
38
|
+
[self sendEventWithName:eventName body:body];
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
[sharedImpl initializeSdk:baseUrl accessToken:accessToken resolve:resolve reject:reject];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 3. NEW: Present the Modal View
|
|
45
|
+
RCT_EXPORT_METHOD(showLuneView:(NSString *)viewIdentifier
|
|
46
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
47
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
48
|
+
{
|
|
49
|
+
[[PfmSdkReactNativeImpl shared] showLuneView:viewIdentifier resolve:resolve reject:reject];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
RCT_EXPORT_METHOD(optInForEventListener:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
|
|
53
|
+
{
|
|
54
|
+
[[PfmSdkReactNativeImpl shared] optInForEventListener:resolve reject:reject];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
RCT_EXPORT_METHOD(optInForErrorLogger:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
|
|
58
|
+
{
|
|
59
|
+
[[PfmSdkReactNativeImpl shared] optInForErrorLogger:resolve reject:reject];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
RCT_EXPORT_METHOD(optInForErrorNotifier:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
|
|
63
|
+
{
|
|
64
|
+
[[PfmSdkReactNativeImpl shared] optInForErrorNotifier:resolve reject:reject];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
RCT_EXPORT_METHOD(optInForSuccessNotifier:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
|
|
68
|
+
{
|
|
69
|
+
[[PfmSdkReactNativeImpl shared] optInForSuccessNotifier:resolve reject:reject];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
RCT_EXPORT_METHOD(registerRefreshTokenCallback:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
|
|
73
|
+
{
|
|
74
|
+
[[PfmSdkReactNativeImpl shared] registerRefreshTokenCallback:resolve reject:reject];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
RCT_EXPORT_METHOD(destroySdk:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
|
|
78
|
+
{
|
|
79
|
+
[[PfmSdkReactNativeImpl shared] destroySdk:resolve reject:reject];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
RCT_EXPORT_METHOD(addListener:(NSString *)eventName) {}
|
|
83
|
+
RCT_EXPORT_METHOD(removeListeners:(double)count) {}
|
|
84
|
+
|
|
85
|
+
+ (BOOL)requiresMainQueueSetup
|
|
86
|
+
{
|
|
87
|
+
return YES;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@end
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import React
|
|
3
|
+
import SwiftUI // <-- Required to present SwiftUI Views!
|
|
4
|
+
import LuneSDK
|
|
5
|
+
|
|
6
|
+
@objc(PfmSdkReactNativeImpl)
|
|
7
|
+
public class PfmSdkReactNativeImpl: NSObject {
|
|
8
|
+
|
|
9
|
+
@objc public static let shared = PfmSdkReactNativeImpl()
|
|
10
|
+
|
|
11
|
+
@objc public var sendEvent: ((String, Any?) -> Void)?
|
|
12
|
+
|
|
13
|
+
var sdkManager: LuneSDKManager?
|
|
14
|
+
|
|
15
|
+
// Cache these to easily pass into the SwiftUI View later
|
|
16
|
+
var savedBaseUrl: String = ""
|
|
17
|
+
var savedToken: String = ""
|
|
18
|
+
|
|
19
|
+
@objc(initializeSdk:accessToken:resolve:reject:)
|
|
20
|
+
public func initializeSdk(baseUrl: String, accessToken: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
21
|
+
// Safety check: ensure the strings aren't empty
|
|
22
|
+
guard !baseUrl.isEmpty, !accessToken.isEmpty else {
|
|
23
|
+
reject("INVALID_PARAMS", "Base URL or Access Token is empty", nil)
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
DispatchQueue.main.async {
|
|
28
|
+
self.savedBaseUrl = baseUrl
|
|
29
|
+
self.savedToken = accessToken
|
|
30
|
+
|
|
31
|
+
// Wrap in a do-catch or check if the LuneSDK expects a specific URL format
|
|
32
|
+
self.sdkManager = LuneSDKManager(baseUrl: baseUrl, token: accessToken)
|
|
33
|
+
|
|
34
|
+
print("Lune SDK Initialized with URL: \(baseUrl)")
|
|
35
|
+
resolve(nil)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// NEW: Cordova-Style Presentation
|
|
40
|
+
@objc(showLuneView:resolve:reject:)
|
|
41
|
+
public func showLuneView(viewIdentifier: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
42
|
+
DispatchQueue.main.async {
|
|
43
|
+
guard self.sdkManager != nil else {
|
|
44
|
+
reject("NOT_INITIALIZED", "Lune SDK is not initialized yet.", nil)
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 1. Create the SwiftUI View
|
|
49
|
+
let swiftUIView = LuneSelectorView(
|
|
50
|
+
viewType: viewIdentifier,
|
|
51
|
+
baseUrl: self.savedBaseUrl,
|
|
52
|
+
token: self.savedToken
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
// 2. Wrap it in a UIViewController
|
|
56
|
+
let hostingController = UIHostingController(rootView: swiftUIView)
|
|
57
|
+
hostingController.modalPresentationStyle = .pageSheet // Creates that nice slide-up modal effect
|
|
58
|
+
|
|
59
|
+
// 3. Find the currently visible View Controller
|
|
60
|
+
guard let windowScene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene,
|
|
61
|
+
let rootVC = windowScene.windows.first(where: { $0.isKeyWindow })?.rootViewController else {
|
|
62
|
+
reject("UI_ERROR", "Could not find root view controller to present Lune View", nil)
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
var topVC = rootVC
|
|
67
|
+
while let presented = topVC.presentedViewController {
|
|
68
|
+
topVC = presented
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// 4. Present it!
|
|
72
|
+
topVC.present(hostingController, animated: true) {
|
|
73
|
+
resolve(nil)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@objc(optInForEventListener:reject:)
|
|
79
|
+
public func optInForEventListener(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
80
|
+
guard let manager = self.sdkManager else {
|
|
81
|
+
reject("NOT_INITIALIZED", "Lune SDK is not initialized yet.", nil)
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
manager.initializeLogger { event in
|
|
85
|
+
self.sendEvent?("onLuneEvent", event)
|
|
86
|
+
}
|
|
87
|
+
resolve(nil)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@objc(optInForErrorLogger:reject:)
|
|
91
|
+
public func optInForErrorLogger(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
92
|
+
self.sdkManager?.setUpErrorLogger { error in
|
|
93
|
+
self.sendEvent?("onLuneError", error.localizedDescription)
|
|
94
|
+
}
|
|
95
|
+
resolve(nil)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@objc(optInForErrorNotifier:reject:)
|
|
99
|
+
public func optInForErrorNotifier(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
100
|
+
self.sdkManager?.setUpErrorNotifier { errorMessage in
|
|
101
|
+
self.sendEvent?("onLuneError", errorMessage)
|
|
102
|
+
}
|
|
103
|
+
resolve(nil)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@objc(optInForSuccessNotifier:reject:)
|
|
107
|
+
public func optInForSuccessNotifier(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
108
|
+
self.sdkManager?.setUpSuccessNotifier { successMessage in
|
|
109
|
+
self.sendEvent?("onLuneSuccess", successMessage)
|
|
110
|
+
}
|
|
111
|
+
resolve(nil)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@objc(registerRefreshTokenCallback:reject:)
|
|
115
|
+
public func registerRefreshTokenCallback(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
116
|
+
self.sdkManager?.setupRefreshCallback {
|
|
117
|
+
self.sendEvent?("onLuneTokenRefresh", nil)
|
|
118
|
+
return nil
|
|
119
|
+
}
|
|
120
|
+
resolve(nil)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
@objc(destroySdk:reject:)
|
|
124
|
+
public func destroySdk(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
125
|
+
self.sdkManager = nil
|
|
126
|
+
self.savedBaseUrl = ""
|
|
127
|
+
self.savedToken = ""
|
|
128
|
+
resolve(nil)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { TurboModuleRegistry } from 'react-native';
|
|
4
|
+
|
|
5
|
+
// This mirrors your Dart LuneViewType enum
|
|
6
|
+
export let LuneViewType = /*#__PURE__*/function (LuneViewType) {
|
|
7
|
+
LuneViewType["CATEGORY_SPEND_CHART"] = "category_spend_chart";
|
|
8
|
+
LuneViewType["CASHFLOW_CHART"] = "cashflow_chart";
|
|
9
|
+
LuneViewType["CATEGORY_TREND_CHART"] = "category_trend_chart";
|
|
10
|
+
LuneViewType["BRAND_TREND_CHART"] = "brand_trend_chart";
|
|
11
|
+
LuneViewType["BRAND_LIST"] = "brand_list";
|
|
12
|
+
LuneViewType["TRANSACTION_LIST"] = "transaction_list";
|
|
13
|
+
LuneViewType["EXPENSE_VIEW"] = "spend";
|
|
14
|
+
LuneViewType["CASHFLOW_VIEW"] = "cashflow";
|
|
15
|
+
LuneViewType["BUDGET_VIEW"] = "budget";
|
|
16
|
+
LuneViewType["BRAND_TRENDS_VIEW"] = "brand_trend";
|
|
17
|
+
LuneViewType["CATEGORY_TREND_VIEW"] = "category_trend";
|
|
18
|
+
return LuneViewType;
|
|
19
|
+
}({});
|
|
20
|
+
|
|
21
|
+
// This mirrors your Dart LunePlatform abstract class
|
|
22
|
+
|
|
23
|
+
export default TurboModuleRegistry.getEnforcing('PfmSdkReactNative');
|
|
24
|
+
//# sourceMappingURL=NativePfmSdkReactNative.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["TurboModuleRegistry","LuneViewType","getEnforcing"],"sourceRoot":"../../src","sources":["NativePfmSdkReactNative.ts"],"mappings":";;AACA,SAASA,mBAAmB,QAAQ,cAAc;;AAElD;AACA,WAAYC,YAAY,0BAAZA,YAAY;EAAZA,YAAY;EAAZA,YAAY;EAAZA,YAAY;EAAZA,YAAY;EAAZA,YAAY;EAAZA,YAAY;EAAZA,YAAY;EAAZA,YAAY;EAAZA,YAAY;EAAZA,YAAY;EAAZA,YAAY;EAAA,OAAZA,YAAY;AAAA;;AAcxB;;AAkBA,eAAeD,mBAAmB,CAACE,YAAY,CAAO,mBAAmB,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { NativeEventEmitter } from 'react-native';
|
|
4
|
+
import PfmSdkReactNative from "./NativePfmSdkReactNative.js";
|
|
5
|
+
|
|
6
|
+
// 1. Export the Types/Enums
|
|
7
|
+
export { LuneViewType } from "./NativePfmSdkReactNative.js";
|
|
8
|
+
|
|
9
|
+
// Create the emitter connected to your native module
|
|
10
|
+
const emitter = new NativeEventEmitter(PfmSdkReactNative);
|
|
11
|
+
|
|
12
|
+
// --- Core Methods ---
|
|
13
|
+
export function initializeSdk(baseUrl, accessToken) {
|
|
14
|
+
return PfmSdkReactNative.initializeSdk(baseUrl, accessToken);
|
|
15
|
+
}
|
|
16
|
+
export function optInForEventListener() {
|
|
17
|
+
return PfmSdkReactNative.optInForEventListener();
|
|
18
|
+
}
|
|
19
|
+
export function optInForErrorLogger() {
|
|
20
|
+
return PfmSdkReactNative.optInForErrorLogger();
|
|
21
|
+
}
|
|
22
|
+
export function optInForErrorNotifier() {
|
|
23
|
+
return PfmSdkReactNative.optInForErrorNotifier();
|
|
24
|
+
}
|
|
25
|
+
export function optInForSuccessNotifier() {
|
|
26
|
+
return PfmSdkReactNative.optInForSuccessNotifier();
|
|
27
|
+
}
|
|
28
|
+
export function registerRefreshTokenCallback() {
|
|
29
|
+
return PfmSdkReactNative.registerRefreshTokenCallback();
|
|
30
|
+
}
|
|
31
|
+
export function destroySdk() {
|
|
32
|
+
return PfmSdkReactNative.destroySdk();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// --- View Presentation Methods (Cordova Style) ---
|
|
36
|
+
export function showLuneView(viewIdentifier) {
|
|
37
|
+
return PfmSdkReactNative.showLuneView(viewIdentifier);
|
|
38
|
+
}
|
|
39
|
+
export function showCashflowComponent() {
|
|
40
|
+
return showLuneView('cashflow');
|
|
41
|
+
}
|
|
42
|
+
export function showBudgetComponent() {
|
|
43
|
+
return showLuneView('budget');
|
|
44
|
+
}
|
|
45
|
+
export function showExpenseComponent() {
|
|
46
|
+
return showLuneView('spend');
|
|
47
|
+
}
|
|
48
|
+
export function showBrandTrendComponent() {
|
|
49
|
+
console.warn('Brand trends not supported on native yet, showing Spend.');
|
|
50
|
+
return showLuneView('spend');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// --- Event Listeners ---
|
|
54
|
+
export function addLuneEventListener(callback) {
|
|
55
|
+
return emitter.addListener('onLuneEvent', event => callback(event));
|
|
56
|
+
}
|
|
57
|
+
export function addLuneErrorListener(callback) {
|
|
58
|
+
return emitter.addListener('onLuneError', error => callback(String(error)));
|
|
59
|
+
}
|
|
60
|
+
export function addLuneSuccessListener(callback) {
|
|
61
|
+
return emitter.addListener('onLuneSuccess', message => callback(String(message)));
|
|
62
|
+
}
|
|
63
|
+
export function addLuneTokenRefreshListener(callback) {
|
|
64
|
+
return emitter.addListener('onLuneTokenRefresh', () => callback());
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["NativeEventEmitter","PfmSdkReactNative","LuneViewType","emitter","initializeSdk","baseUrl","accessToken","optInForEventListener","optInForErrorLogger","optInForErrorNotifier","optInForSuccessNotifier","registerRefreshTokenCallback","destroySdk","showLuneView","viewIdentifier","showCashflowComponent","showBudgetComponent","showExpenseComponent","showBrandTrendComponent","console","warn","addLuneEventListener","callback","addListener","event","addLuneErrorListener","error","String","addLuneSuccessListener","message","addLuneTokenRefreshListener"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,kBAAkB,QAAQ,cAAc;AAEjD,OAAOC,iBAAiB,MAAM,8BAA2B;;AAEzD;AACA,SAASC,YAAY,QAAQ,8BAA2B;;AAExD;AACA,MAAMC,OAAO,GAAG,IAAIH,kBAAkB,CAACC,iBAAwB,CAAC;;AAEhE;AACA,OAAO,SAASG,aAAaA,CAC3BC,OAAe,EACfC,WAAmB,EACJ;EACf,OAAOL,iBAAiB,CAACG,aAAa,CAACC,OAAO,EAAEC,WAAW,CAAC;AAC9D;AAEA,OAAO,SAASC,qBAAqBA,CAAA,EAAkB;EACrD,OAAON,iBAAiB,CAACM,qBAAqB,CAAC,CAAC;AAClD;AAEA,OAAO,SAASC,mBAAmBA,CAAA,EAAkB;EACnD,OAAOP,iBAAiB,CAACO,mBAAmB,CAAC,CAAC;AAChD;AAEA,OAAO,SAASC,qBAAqBA,CAAA,EAAkB;EACrD,OAAOR,iBAAiB,CAACQ,qBAAqB,CAAC,CAAC;AAClD;AAEA,OAAO,SAASC,uBAAuBA,CAAA,EAAkB;EACvD,OAAOT,iBAAiB,CAACS,uBAAuB,CAAC,CAAC;AACpD;AAEA,OAAO,SAASC,4BAA4BA,CAAA,EAAkB;EAC5D,OAAOV,iBAAiB,CAACU,4BAA4B,CAAC,CAAC;AACzD;AAEA,OAAO,SAASC,UAAUA,CAAA,EAAkB;EAC1C,OAAOX,iBAAiB,CAACW,UAAU,CAAC,CAAC;AACvC;;AAEA;AACA,OAAO,SAASC,YAAYA,CAACC,cAAsB,EAAiB;EAClE,OAAOb,iBAAiB,CAACY,YAAY,CAACC,cAAc,CAAC;AACvD;AAEA,OAAO,SAASC,qBAAqBA,CAAA,EAAkB;EACrD,OAAOF,YAAY,CAAC,UAAU,CAAC;AACjC;AAEA,OAAO,SAASG,mBAAmBA,CAAA,EAAkB;EACnD,OAAOH,YAAY,CAAC,QAAQ,CAAC;AAC/B;AAEA,OAAO,SAASI,oBAAoBA,CAAA,EAAkB;EACpD,OAAOJ,YAAY,CAAC,OAAO,CAAC;AAC9B;AAEA,OAAO,SAASK,uBAAuBA,CAAA,EAAkB;EACvDC,OAAO,CAACC,IAAI,CAAC,0DAA0D,CAAC;EACxE,OAAOP,YAAY,CAAC,OAAO,CAAC;AAC9B;;AAEA;AACA,OAAO,SAASQ,oBAAoBA,CAClCC,QAA8B,EACX;EACnB,OAAOnB,OAAO,CAACoB,WAAW,CAAC,aAAa,EAAGC,KAAU,IAAKF,QAAQ,CAACE,KAAK,CAAC,CAAC;AAC5E;AAEA,OAAO,SAASC,oBAAoBA,CAClCH,QAAiC,EACd;EACnB,OAAOnB,OAAO,CAACoB,WAAW,CAAC,aAAa,EAAGG,KAAU,IACnDJ,QAAQ,CAACK,MAAM,CAACD,KAAK,CAAC,CACxB,CAAC;AACH;AAEA,OAAO,SAASE,sBAAsBA,CACpCN,QAAmC,EAChB;EACnB,OAAOnB,OAAO,CAACoB,WAAW,CAAC,eAAe,EAAGM,OAAY,IACvDP,QAAQ,CAACK,MAAM,CAACE,OAAO,CAAC,CAC1B,CAAC;AACH;AAEA,OAAO,SAASC,2BAA2BA,CACzCR,QAAoB,EACD;EACnB,OAAOnB,OAAO,CAACoB,WAAW,CAAC,oBAAoB,EAAE,MAAMD,QAAQ,CAAC,CAAC,CAAC;AACpE","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { TurboModule } from 'react-native';
|
|
2
|
+
export declare enum LuneViewType {
|
|
3
|
+
CATEGORY_SPEND_CHART = "category_spend_chart",
|
|
4
|
+
CASHFLOW_CHART = "cashflow_chart",
|
|
5
|
+
CATEGORY_TREND_CHART = "category_trend_chart",
|
|
6
|
+
BRAND_TREND_CHART = "brand_trend_chart",
|
|
7
|
+
BRAND_LIST = "brand_list",
|
|
8
|
+
TRANSACTION_LIST = "transaction_list",
|
|
9
|
+
EXPENSE_VIEW = "spend",
|
|
10
|
+
CASHFLOW_VIEW = "cashflow",
|
|
11
|
+
BUDGET_VIEW = "budget",
|
|
12
|
+
BRAND_TRENDS_VIEW = "brand_trend",
|
|
13
|
+
CATEGORY_TREND_VIEW = "category_trend"
|
|
14
|
+
}
|
|
15
|
+
export interface Spec extends TurboModule {
|
|
16
|
+
initializeSdk(baseUrl: string, accessToken: string): Promise<void>;
|
|
17
|
+
optInForEventListener(): Promise<void>;
|
|
18
|
+
optInForErrorLogger(): Promise<void>;
|
|
19
|
+
optInForErrorNotifier(): Promise<void>;
|
|
20
|
+
optInForSuccessNotifier(): Promise<void>;
|
|
21
|
+
registerRefreshTokenCallback(): Promise<void>;
|
|
22
|
+
destroySdk(): Promise<void>;
|
|
23
|
+
showLuneView(viewIdentifier: string): Promise<void>;
|
|
24
|
+
addListener(eventName: string): void;
|
|
25
|
+
removeListeners(count: number): void;
|
|
26
|
+
}
|
|
27
|
+
declare const _default: Spec;
|
|
28
|
+
export default _default;
|
|
29
|
+
//# sourceMappingURL=NativePfmSdkReactNative.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NativePfmSdkReactNative.d.ts","sourceRoot":"","sources":["../../../src/NativePfmSdkReactNative.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAIhD,oBAAY,YAAY;IACtB,oBAAoB,yBAAyB;IAC7C,cAAc,mBAAmB;IACjC,oBAAoB,yBAAyB;IAC7C,iBAAiB,sBAAsB;IACvC,UAAU,eAAe;IACzB,gBAAgB,qBAAqB;IACrC,YAAY,UAAU;IACtB,aAAa,aAAa;IAC1B,WAAW,WAAW;IACtB,iBAAiB,gBAAgB;IACjC,mBAAmB,mBAAmB;CACvC;AAGD,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,uBAAuB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,4BAA4B,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAG5B,YAAY,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAGpD,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;;AAED,wBAA2E"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { EventSubscription } from 'react-native';
|
|
2
|
+
export { LuneViewType } from './NativePfmSdkReactNative';
|
|
3
|
+
export declare function initializeSdk(baseUrl: string, accessToken: string): Promise<void>;
|
|
4
|
+
export declare function optInForEventListener(): Promise<void>;
|
|
5
|
+
export declare function optInForErrorLogger(): Promise<void>;
|
|
6
|
+
export declare function optInForErrorNotifier(): Promise<void>;
|
|
7
|
+
export declare function optInForSuccessNotifier(): Promise<void>;
|
|
8
|
+
export declare function registerRefreshTokenCallback(): Promise<void>;
|
|
9
|
+
export declare function destroySdk(): Promise<void>;
|
|
10
|
+
export declare function showLuneView(viewIdentifier: string): Promise<void>;
|
|
11
|
+
export declare function showCashflowComponent(): Promise<void>;
|
|
12
|
+
export declare function showBudgetComponent(): Promise<void>;
|
|
13
|
+
export declare function showExpenseComponent(): Promise<void>;
|
|
14
|
+
export declare function showBrandTrendComponent(): Promise<void>;
|
|
15
|
+
export declare function addLuneEventListener(callback: (event: any) => void): EventSubscription;
|
|
16
|
+
export declare function addLuneErrorListener(callback: (error: string) => void): EventSubscription;
|
|
17
|
+
export declare function addLuneSuccessListener(callback: (message: string) => void): EventSubscription;
|
|
18
|
+
export declare function addLuneTokenRefreshListener(callback: () => void): EventSubscription;
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAItD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAMzD,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAgB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAErD;AAED,wBAAgB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAEnD;AAED,wBAAgB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAErD;AAED,wBAAgB,uBAAuB,IAAI,OAAO,CAAC,IAAI,CAAC,CAEvD;AAED,wBAAgB,4BAA4B,IAAI,OAAO,CAAC,IAAI,CAAC,CAE5D;AAED,wBAAgB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAE1C;AAGD,wBAAgB,YAAY,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAElE;AAED,wBAAgB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAErD;AAED,wBAAgB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAEnD;AAED,wBAAgB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAEpD;AAED,wBAAgB,uBAAuB,IAAI,OAAO,CAAC,IAAI,CAAC,CAGvD;AAGD,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,GAC7B,iBAAiB,CAEnB;AAED,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAChC,iBAAiB,CAInB;AAED,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAClC,iBAAiB,CAInB;AAED,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,IAAI,GACnB,iBAAiB,CAEnB"}
|
package/package.json
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "react-native-pfm-sdk-react-native",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "React native plugin that intergates with native iOS and Android SDKs",
|
|
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-native-pfm-sdk-react-native-example",
|
|
36
|
+
"clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
|
|
37
|
+
"prepare": "bob build",
|
|
38
|
+
"typecheck": "tsc",
|
|
39
|
+
"lint": "eslint \"**/*.{js,ts,tsx}\"",
|
|
40
|
+
"test": "jest",
|
|
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://github.com/eslam-ali-ios-lune/react-native-pfm-sdk-react-native.git"
|
|
51
|
+
},
|
|
52
|
+
"author": "Eslam Ali <eslam.ali@lunedata.io> (https://github.com/eslam-ali-ios-lune)",
|
|
53
|
+
"license": "MIT",
|
|
54
|
+
"bugs": {
|
|
55
|
+
"url": "https://github.com/eslam-ali-ios-lune/react-native-pfm-sdk-react-native/issues"
|
|
56
|
+
},
|
|
57
|
+
"homepage": "https://github.com/eslam-ali-ios-lune/react-native-pfm-sdk-react-native#readme",
|
|
58
|
+
"publishConfig": {
|
|
59
|
+
"registry": "https://registry.npmjs.org/"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@commitlint/config-conventional": "^19.8.1",
|
|
63
|
+
"@eslint/compat": "^1.3.2",
|
|
64
|
+
"@eslint/eslintrc": "^3.3.1",
|
|
65
|
+
"@eslint/js": "^9.35.0",
|
|
66
|
+
"@react-native/babel-preset": "0.83.0",
|
|
67
|
+
"@react-native/eslint-config": "0.83.0",
|
|
68
|
+
"@release-it/conventional-changelog": "^10.0.1",
|
|
69
|
+
"@types/jest": "^29.5.14",
|
|
70
|
+
"@types/react": "^19.2.0",
|
|
71
|
+
"commitlint": "^19.8.1",
|
|
72
|
+
"del-cli": "^6.0.0",
|
|
73
|
+
"eslint": "^9.35.0",
|
|
74
|
+
"eslint-config-prettier": "^10.1.8",
|
|
75
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
76
|
+
"jest": "^29.7.0",
|
|
77
|
+
"lefthook": "^2.0.3",
|
|
78
|
+
"prettier": "^2.8.8",
|
|
79
|
+
"react": "19.2.0",
|
|
80
|
+
"react-native": "0.83.0",
|
|
81
|
+
"react-native-builder-bob": "^0.40.13",
|
|
82
|
+
"release-it": "^19.0.4",
|
|
83
|
+
"turbo": "^2.5.6",
|
|
84
|
+
"typescript": "^5.9.2"
|
|
85
|
+
},
|
|
86
|
+
"peerDependencies": {
|
|
87
|
+
"react": "*",
|
|
88
|
+
"react-native": "*"
|
|
89
|
+
},
|
|
90
|
+
"workspaces": {
|
|
91
|
+
"packages": [
|
|
92
|
+
"example"
|
|
93
|
+
],
|
|
94
|
+
"nohoist": [
|
|
95
|
+
"**/@react-native-async-storage/async-storage",
|
|
96
|
+
"**/@react-native-async-storage/async-storage/**"
|
|
97
|
+
]
|
|
98
|
+
},
|
|
99
|
+
"packageManager": "yarn@4.11.0",
|
|
100
|
+
"react-native-builder-bob": {
|
|
101
|
+
"source": "src",
|
|
102
|
+
"output": "lib",
|
|
103
|
+
"targets": [
|
|
104
|
+
[
|
|
105
|
+
"module",
|
|
106
|
+
{
|
|
107
|
+
"esm": true
|
|
108
|
+
}
|
|
109
|
+
],
|
|
110
|
+
[
|
|
111
|
+
"typescript",
|
|
112
|
+
{
|
|
113
|
+
"project": "tsconfig.build.json"
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
]
|
|
117
|
+
},
|
|
118
|
+
"codegenConfig": {
|
|
119
|
+
"name": "RNPfmSdkReactNativeSpec",
|
|
120
|
+
"type": "modules",
|
|
121
|
+
"jsSrcsDir": "src",
|
|
122
|
+
"android": {
|
|
123
|
+
"javaPackageName": "com.pfmsdkreactnative"
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
"prettier": {
|
|
127
|
+
"quoteProps": "consistent",
|
|
128
|
+
"singleQuote": true,
|
|
129
|
+
"tabWidth": 2,
|
|
130
|
+
"trailingComma": "es5",
|
|
131
|
+
"useTabs": false
|
|
132
|
+
},
|
|
133
|
+
"jest": {
|
|
134
|
+
"preset": "react-native",
|
|
135
|
+
"modulePathIgnorePatterns": [
|
|
136
|
+
"<rootDir>/example/node_modules",
|
|
137
|
+
"<rootDir>/lib/"
|
|
138
|
+
]
|
|
139
|
+
},
|
|
140
|
+
"commitlint": {
|
|
141
|
+
"extends": [
|
|
142
|
+
"@commitlint/config-conventional"
|
|
143
|
+
]
|
|
144
|
+
},
|
|
145
|
+
"release-it": {
|
|
146
|
+
"git": {
|
|
147
|
+
"commitMessage": "chore: release ${version}",
|
|
148
|
+
"tagName": "v${version}"
|
|
149
|
+
},
|
|
150
|
+
"npm": {
|
|
151
|
+
"publish": true
|
|
152
|
+
},
|
|
153
|
+
"github": {
|
|
154
|
+
"release": true
|
|
155
|
+
},
|
|
156
|
+
"plugins": {
|
|
157
|
+
"@release-it/conventional-changelog": {
|
|
158
|
+
"preset": {
|
|
159
|
+
"name": "angular"
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
"create-react-native-library": {
|
|
165
|
+
"type": "turbo-module",
|
|
166
|
+
"languages": "kotlin-objc",
|
|
167
|
+
"tools": [
|
|
168
|
+
"eslint",
|
|
169
|
+
"jest",
|
|
170
|
+
"lefthook",
|
|
171
|
+
"release-it"
|
|
172
|
+
],
|
|
173
|
+
"version": "0.57.2"
|
|
174
|
+
}
|
|
175
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { TurboModule } from 'react-native';
|
|
2
|
+
import { TurboModuleRegistry } from 'react-native';
|
|
3
|
+
|
|
4
|
+
// This mirrors your Dart LuneViewType enum
|
|
5
|
+
export enum LuneViewType {
|
|
6
|
+
CATEGORY_SPEND_CHART = 'category_spend_chart',
|
|
7
|
+
CASHFLOW_CHART = 'cashflow_chart',
|
|
8
|
+
CATEGORY_TREND_CHART = 'category_trend_chart',
|
|
9
|
+
BRAND_TREND_CHART = 'brand_trend_chart',
|
|
10
|
+
BRAND_LIST = 'brand_list',
|
|
11
|
+
TRANSACTION_LIST = 'transaction_list',
|
|
12
|
+
EXPENSE_VIEW = 'spend',
|
|
13
|
+
CASHFLOW_VIEW = 'cashflow',
|
|
14
|
+
BUDGET_VIEW = 'budget',
|
|
15
|
+
BRAND_TRENDS_VIEW = 'brand_trend',
|
|
16
|
+
CATEGORY_TREND_VIEW = 'category_trend',
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// This mirrors your Dart LunePlatform abstract class
|
|
20
|
+
export interface Spec extends TurboModule {
|
|
21
|
+
initializeSdk(baseUrl: string, accessToken: string): Promise<void>;
|
|
22
|
+
optInForEventListener(): Promise<void>;
|
|
23
|
+
optInForErrorLogger(): Promise<void>;
|
|
24
|
+
optInForErrorNotifier(): Promise<void>;
|
|
25
|
+
optInForSuccessNotifier(): Promise<void>;
|
|
26
|
+
registerRefreshTokenCallback(): Promise<void>;
|
|
27
|
+
destroySdk(): Promise<void>;
|
|
28
|
+
|
|
29
|
+
// 🚀 NEW METHOD ADDED HERE:
|
|
30
|
+
showLuneView(viewIdentifier: string): Promise<void>;
|
|
31
|
+
|
|
32
|
+
// REQUIRED FOR EVENT EMITTERS:
|
|
33
|
+
addListener(eventName: string): void;
|
|
34
|
+
removeListeners(count: number): void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default TurboModuleRegistry.getEnforcing<Spec>('PfmSdkReactNative');
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { NativeEventEmitter } from 'react-native';
|
|
2
|
+
import type { EventSubscription } from 'react-native';
|
|
3
|
+
import PfmSdkReactNative from './NativePfmSdkReactNative';
|
|
4
|
+
|
|
5
|
+
// 1. Export the Types/Enums
|
|
6
|
+
export { LuneViewType } from './NativePfmSdkReactNative';
|
|
7
|
+
|
|
8
|
+
// Create the emitter connected to your native module
|
|
9
|
+
const emitter = new NativeEventEmitter(PfmSdkReactNative as any);
|
|
10
|
+
|
|
11
|
+
// --- Core Methods ---
|
|
12
|
+
export function initializeSdk(
|
|
13
|
+
baseUrl: string,
|
|
14
|
+
accessToken: string
|
|
15
|
+
): Promise<void> {
|
|
16
|
+
return PfmSdkReactNative.initializeSdk(baseUrl, accessToken);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function optInForEventListener(): Promise<void> {
|
|
20
|
+
return PfmSdkReactNative.optInForEventListener();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function optInForErrorLogger(): Promise<void> {
|
|
24
|
+
return PfmSdkReactNative.optInForErrorLogger();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function optInForErrorNotifier(): Promise<void> {
|
|
28
|
+
return PfmSdkReactNative.optInForErrorNotifier();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function optInForSuccessNotifier(): Promise<void> {
|
|
32
|
+
return PfmSdkReactNative.optInForSuccessNotifier();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function registerRefreshTokenCallback(): Promise<void> {
|
|
36
|
+
return PfmSdkReactNative.registerRefreshTokenCallback();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function destroySdk(): Promise<void> {
|
|
40
|
+
return PfmSdkReactNative.destroySdk();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// --- View Presentation Methods (Cordova Style) ---
|
|
44
|
+
export function showLuneView(viewIdentifier: string): Promise<void> {
|
|
45
|
+
return PfmSdkReactNative.showLuneView(viewIdentifier);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function showCashflowComponent(): Promise<void> {
|
|
49
|
+
return showLuneView('cashflow');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function showBudgetComponent(): Promise<void> {
|
|
53
|
+
return showLuneView('budget');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function showExpenseComponent(): Promise<void> {
|
|
57
|
+
return showLuneView('spend');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function showBrandTrendComponent(): Promise<void> {
|
|
61
|
+
console.warn('Brand trends not supported on native yet, showing Spend.');
|
|
62
|
+
return showLuneView('spend');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// --- Event Listeners ---
|
|
66
|
+
export function addLuneEventListener(
|
|
67
|
+
callback: (event: any) => void
|
|
68
|
+
): EventSubscription {
|
|
69
|
+
return emitter.addListener('onLuneEvent', (event: any) => callback(event));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function addLuneErrorListener(
|
|
73
|
+
callback: (error: string) => void
|
|
74
|
+
): EventSubscription {
|
|
75
|
+
return emitter.addListener('onLuneError', (error: any) =>
|
|
76
|
+
callback(String(error))
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function addLuneSuccessListener(
|
|
81
|
+
callback: (message: string) => void
|
|
82
|
+
): EventSubscription {
|
|
83
|
+
return emitter.addListener('onLuneSuccess', (message: any) =>
|
|
84
|
+
callback(String(message))
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function addLuneTokenRefreshListener(
|
|
89
|
+
callback: () => void
|
|
90
|
+
): EventSubscription {
|
|
91
|
+
return emitter.addListener('onLuneTokenRefresh', () => callback());
|
|
92
|
+
}
|