@dashx/react-native 1.5.0 → 1.5.1

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 (85) hide show
  1. package/README.md +1 -1
  2. package/ios/DashXReactNative.mm +7 -7
  3. package/ios/DashXReactNative.swift +15 -11
  4. package/package.json +13 -11
  5. package/.claude/settings.local.json +0 -7
  6. package/.claude/worktrees/autocapture-conventions-review-78f665/.gitattributes +0 -1
  7. package/.claude/worktrees/autocapture-conventions-review-78f665/.github/workflows/ci.yml +0 -67
  8. package/.claude/worktrees/autocapture-conventions-review-78f665/.gitignore +0 -49
  9. package/.claude/worktrees/autocapture-conventions-review-78f665/.nvmrc +0 -1
  10. package/.claude/worktrees/autocapture-conventions-review-78f665/CHANGELOG.md +0 -144
  11. package/.claude/worktrees/autocapture-conventions-review-78f665/CONTRIBUTING.md +0 -190
  12. package/.claude/worktrees/autocapture-conventions-review-78f665/DashXReactNative.podspec +0 -38
  13. package/.claude/worktrees/autocapture-conventions-review-78f665/LICENSE +0 -21
  14. package/.claude/worktrees/autocapture-conventions-review-78f665/README.md +0 -97
  15. package/.claude/worktrees/autocapture-conventions-review-78f665/__tests__/fallback.test.js +0 -72
  16. package/.claude/worktrees/autocapture-conventions-review-78f665/__tests__/index.test.js +0 -702
  17. package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gitignore +0 -10
  18. package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gradle/8.14.3/checksums/checksums.lock +0 -0
  19. package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gradle/8.14.3/fileChanges/last-build.bin +0 -0
  20. package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gradle/8.14.3/fileHashes/fileHashes.lock +0 -0
  21. package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gradle/8.14.3/gc.properties +0 -0
  22. package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  23. package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gradle/buildOutputCleanup/cache.properties +0 -2
  24. package/.claude/worktrees/autocapture-conventions-review-78f665/android/.gradle/vcs-1/gc.properties +0 -0
  25. package/.claude/worktrees/autocapture-conventions-review-78f665/android/build/reports/problems/problems-report.html +0 -663
  26. package/.claude/worktrees/autocapture-conventions-review-78f665/android/build.gradle +0 -121
  27. package/.claude/worktrees/autocapture-conventions-review-78f665/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  28. package/.claude/worktrees/autocapture-conventions-review-78f665/android/gradle/wrapper/gradle-wrapper.properties +0 -6
  29. package/.claude/worktrees/autocapture-conventions-review-78f665/android/gradle.properties +0 -1
  30. package/.claude/worktrees/autocapture-conventions-review-78f665/android/gradlew +0 -185
  31. package/.claude/worktrees/autocapture-conventions-review-78f665/android/gradlew.bat +0 -89
  32. package/.claude/worktrees/autocapture-conventions-review-78f665/android/settings.gradle +0 -27
  33. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/AndroidManifest.xml +0 -19
  34. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/java/com/dashx/rn/sdk/DashXNotificationClickedListener.kt +0 -113
  35. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/java/com/dashx/rn/sdk/DashXReactNativeFirebaseMessagingService.kt +0 -72
  36. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/java/com/dashx/rn/sdk/DashXReactNativeModuleImpl.kt +0 -445
  37. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/java/com/dashx/rn/sdk/MessageReceivedEventHolder.kt +0 -14
  38. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/java/com/dashx/rn/sdk/ReactNativeLibraryInfoProvider.kt +0 -8
  39. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/java/com/dashx/rn/sdk/util/Utils.kt +0 -208
  40. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/main/resources/META-INF/services/com.dashx.android.DashXLibraryInfoProvider +0 -1
  41. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/newarch/java/com/dashx/rn/sdk/DashXReactNativeModule.kt +0 -85
  42. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/newarch/java/com/dashx/rn/sdk/DashXReactNativePackage.kt +0 -33
  43. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/oldarch/java/com/dashx/rn/sdk/DashXReactNativeModule.kt +0 -106
  44. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/oldarch/java/com/dashx/rn/sdk/DashXReactNativePackage.kt +0 -33
  45. package/.claude/worktrees/autocapture-conventions-review-78f665/android/src/test/java/com/dashx/rn/sdk/util/UtilsTest.kt +0 -305
  46. package/.claude/worktrees/autocapture-conventions-review-78f665/babel.config.js +0 -3
  47. package/.claude/worktrees/autocapture-conventions-review-78f665/index.d.ts +0 -321
  48. package/.claude/worktrees/autocapture-conventions-review-78f665/index.js +0 -300
  49. package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXEventEmitter.swift +0 -15
  50. package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXNotificationHandler.swift +0 -301
  51. package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXReactNative-Bridging-Header.h +0 -3
  52. package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXReactNative.mm +0 -77
  53. package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXReactNative.swift +0 -244
  54. package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXReactNative.xcodeproj/project.pbxproj +0 -280
  55. package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXReactNative.xcworkspace/contents.xcworkspacedata +0 -7
  56. package/.claude/worktrees/autocapture-conventions-review-78f665/ios/DashXReactNative.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  57. package/.claude/worktrees/autocapture-conventions-review-78f665/package.json +0 -123
  58. package/.claude/worktrees/autocapture-conventions-review-78f665/scripts/generate-bridge-shim.js +0 -259
  59. package/.claude/worktrees/autocapture-conventions-review-78f665/src/NativeDashXReactNative.ts +0 -42
  60. package/.claude/worktrees/autocapture-conventions-review-78f665/yarn.lock +0 -6244
  61. package/.gitattributes +0 -1
  62. package/.github/workflows/ci.yml +0 -67
  63. package/.gitignore +0 -49
  64. package/.nvmrc +0 -1
  65. package/CHANGELOG.md +0 -144
  66. package/CONTRIBUTING.md +0 -190
  67. package/__tests__/fallback.test.js +0 -72
  68. package/__tests__/index.test.js +0 -702
  69. package/android/.gitignore +0 -10
  70. package/android/.gradle/8.14.3/checksums/checksums.lock +0 -0
  71. package/android/.gradle/8.14.3/fileChanges/last-build.bin +0 -0
  72. package/android/.gradle/8.14.3/fileHashes/fileHashes.lock +0 -0
  73. package/android/.gradle/8.14.3/gc.properties +0 -0
  74. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  75. package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
  76. package/android/.gradle/vcs-1/gc.properties +0 -0
  77. package/android/build/reports/problems/problems-report.html +0 -663
  78. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  79. package/android/gradle/wrapper/gradle-wrapper.properties +0 -6
  80. package/android/gradlew +0 -185
  81. package/android/gradlew.bat +0 -89
  82. package/android/src/test/java/com/dashx/rn/sdk/util/UtilsTest.kt +0 -305
  83. package/babel.config.js +0 -3
  84. package/scripts/generate-bridge-shim.js +0 -259
  85. package/yarn.lock +0 -6244
@@ -1,301 +0,0 @@
1
- import Foundation
2
- import UIKit
3
- import UserNotifications
4
- import DashX
5
- import FirebaseMessaging
6
-
7
- /// The result of handling a notification response.
8
- /// Consumers can use `url` to navigate and `actionIdentifier` for custom action handling.
9
- @objc(DashXNotificationResponseResult)
10
- public final class DashXNotificationResponseResult: NSObject {
11
- @objc public let userInfo: [AnyHashable: Any]
12
- @objc public let actionIdentifier: String
13
- /// The DashX notification URL, if present in the payload.
14
- @objc public let url: URL?
15
- /// The resolved navigation intent for the tap / action button.
16
- /// Non-@objc (the enum isn't representable in Obj-C); read via Swift.
17
- public let navigationAction: NavigationAction?
18
-
19
- init(userInfo: [AnyHashable: Any], actionIdentifier: String, url: URL?, navigationAction: NavigationAction?) {
20
- self.userInfo = userInfo
21
- self.actionIdentifier = actionIdentifier
22
- self.url = url
23
- self.navigationAction = navigationAction
24
- }
25
- }
26
-
27
- @objc(DashXNotificationHandler)
28
- public final class DashXNotificationHandler: NSObject {
29
-
30
- @objc
31
- public static func handleRemoteNotification(
32
- userInfo: [AnyHashable: Any],
33
- completionHandler: @escaping (UIBackgroundFetchResult) -> Void
34
- ) {
35
- Messaging.messaging().appDidReceiveMessage(userInfo)
36
-
37
- DashXEventEmitter.instance.dispatch(
38
- name: "messageReceived",
39
- body: bridgeSafePayload(from: userInfo)
40
- )
41
-
42
- // Alert pushes (aps.alert present) are displayed by iOS directly via
43
- // the Notification Service Extension. Skipping the silent-push
44
- // reconstruction prevents a duplicate `add()` from racing the
45
- // system-displayed banner and clobbering its NSE-attached image.
46
- if let aps = userInfo["aps"] as? [AnyHashable: Any], aps["alert"] != nil {
47
- completionHandler(.newData)
48
- return
49
- }
50
-
51
- guard let dashxData = userInfo.dashxNotificationData() else {
52
- completionHandler(.noData)
53
- return
54
- }
55
-
56
- DashX.trackMessage(message: userInfo, event: .delivered)
57
-
58
- let content = UNMutableNotificationContent()
59
- content.sound = UNNotificationSound.default
60
- content.title = dashxData.title
61
- content.body = dashxData.body
62
- content.userInfo = userInfo
63
- content.categoryIdentifier = Constants.DASHX_NOTIFICATION_CATEGORY_IDENTIFIER
64
-
65
- var actions: [UNNotificationAction] = []
66
- if let actionButtons = dashxData.actionButtons {
67
- for button in actionButtons {
68
- actions.append(
69
- UNNotificationAction(
70
- identifier: button.identifier,
71
- title: button.label,
72
- options: [.foreground]
73
- )
74
- )
75
- }
76
- }
77
-
78
- let category = UNNotificationCategory(
79
- identifier: Constants.DASHX_NOTIFICATION_CATEGORY_IDENTIFIER,
80
- actions: actions,
81
- intentIdentifiers: [],
82
- options: .customDismissAction
83
- )
84
- UNUserNotificationCenter.current().setNotificationCategories([category])
85
-
86
- // Defer the completion handler until after the local notification has
87
- // actually been added. iOS suspends the process the moment we call
88
- // `completionHandler`, so firing it before the async download + add
89
- // chain finishes was dropping notifications mid-flight. The 25s budget
90
- // sits comfortably under iOS's ~30s background-push limit.
91
- let fire = makeOnceFire(completionHandler)
92
- DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(25)) {
93
- fire(.newData)
94
- }
95
-
96
- if let imagePath = dashxData.image, let imageURL = URL(string: imagePath) {
97
- createNotificationWithImage(id: dashxData.id, imageURL: imageURL, content: content) {
98
- fire(.newData)
99
- }
100
- } else {
101
- createNotification(id: dashxData.id, content: content) {
102
- fire(.newData)
103
- }
104
- }
105
- }
106
-
107
- /// Wraps `completionHandler` so it can be invoked safely from any of the
108
- /// (download done) / (add done) / (timeout) callbacks — second invocation
109
- /// is a no-op.
110
- private static func makeOnceFire(
111
- _ completionHandler: @escaping (UIBackgroundFetchResult) -> Void
112
- ) -> (UIBackgroundFetchResult) -> Void {
113
- let lock = NSLock()
114
- var fired = false
115
- return { result in
116
- lock.lock()
117
- defer { lock.unlock() }
118
- guard !fired else { return }
119
- fired = true
120
- completionHandler(result)
121
- }
122
- }
123
-
124
- @objc
125
- @discardableResult
126
- public static func handleNotificationResponse(_ response: UNNotificationResponse) -> DashXNotificationResponseResult {
127
- let userInfo = response.notification.request.content.userInfo
128
-
129
- Messaging.messaging().appDidReceiveMessage(userInfo)
130
-
131
- DashXEventEmitter.instance.dispatch(
132
- name: "messageReceived",
133
- body: bridgeSafePayload(from: userInfo)
134
- )
135
-
136
- if response.actionIdentifier == UNNotificationDismissActionIdentifier {
137
- DashX.trackMessage(message: userInfo, event: .dismissed)
138
- } else {
139
- DashX.trackMessage(message: userInfo, event: .clicked)
140
- }
141
-
142
- let notificationUrl = userInfo.dashxNotificationUrl()
143
- let dashxData = userInfo.dashxNotificationData()
144
- let navigationAction = dashxData?.navigationAction(forActionIdentifier: response.actionIdentifier)
145
-
146
- if response.actionIdentifier != UNNotificationDismissActionIdentifier {
147
- DashXEventEmitter.instance.dispatch(
148
- name: "notificationClicked",
149
- body: [
150
- "notification": bridgeSafePayload(from: userInfo),
151
- "action": jsonDictionary(from: navigationAction) ?? NSNull(),
152
- "actionIdentifier": response.actionIdentifier,
153
- ]
154
- )
155
- }
156
-
157
- return DashXNotificationResponseResult(
158
- userInfo: userInfo,
159
- actionIdentifier: response.actionIdentifier,
160
- url: notificationUrl,
161
- navigationAction: navigationAction
162
- )
163
- }
164
-
165
- // MARK: - Device Token
166
-
167
- /// Bridges the APNS device token to Firebase Cloud Messaging and registers
168
- /// the FCM token with DashX. Call this from
169
- /// `application(_:didRegisterForRemoteNotificationsWithDeviceToken:)`.
170
- @objc
171
- public static func handleDeviceToken(_ deviceToken: Data) {
172
- // Force the APNs environment explicitly rather than using `.unknown`
173
- // (auto-detect). Firebase's auto-detection reads the token's aps
174
- // entitlement from the signed binary and sometimes mis-tags dev
175
- // builds as production, producing an FCM token whose pushes silently
176
- // fail at APNs with 410 Unregistered.
177
- #if DEBUG
178
- Messaging.messaging().setAPNSToken(deviceToken, type: .sandbox)
179
- #else
180
- Messaging.messaging().setAPNSToken(deviceToken, type: .prod)
181
- #endif
182
- Messaging.messaging().token { token, error in
183
- if let token = token {
184
- DashX.setFCMToken(to: token)
185
- }
186
- }
187
- }
188
-
189
- // MARK: - Foreground Notification
190
-
191
- /// Handles a notification that arrived while the app is in the foreground.
192
- /// Tracks the delivery event, emits `messageReceived` to JS, forwards to
193
- /// Firebase analytics, and presents the notification as a banner with sound.
194
- /// Call this from `userNotificationCenter(_:willPresent:withCompletionHandler:)`.
195
- @objc
196
- public static func handleForegroundNotification(
197
- _ notification: UNNotification,
198
- completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
199
- ) {
200
- let userInfo = notification.request.content.userInfo
201
-
202
- Messaging.messaging().appDidReceiveMessage(userInfo)
203
-
204
- DashX.trackMessage(message: userInfo, event: .delivered)
205
-
206
- DashXEventEmitter.instance.dispatch(
207
- name: "messageReceived",
208
- body: bridgeSafePayload(from: userInfo)
209
- )
210
-
211
- completionHandler([.banner, .sound])
212
- }
213
-
214
- // MARK: - Private Helpers
215
-
216
- private static func createNotification(
217
- id: String,
218
- content: UNMutableNotificationContent,
219
- completion: @escaping () -> Void
220
- ) {
221
- let request = UNNotificationRequest(identifier: id, content: content, trigger: nil)
222
- UNUserNotificationCenter.current().add(request) { error in
223
- if let error = error {
224
- DashXLog.d(tag: #function, "Failed to schedule notification: \(error.localizedDescription)")
225
- }
226
- completion()
227
- }
228
- }
229
-
230
- private static func createNotificationWithImage(
231
- id: String,
232
- imageURL: URL,
233
- content: UNMutableNotificationContent,
234
- completion: @escaping () -> Void
235
- ) {
236
- let task = URLSession.shared.downloadTask(with: imageURL) { location, _, error in
237
- guard let location = location, error == nil else {
238
- createNotification(id: id, content: content, completion: completion)
239
- return
240
- }
241
-
242
- let tmpDir = FileManager.default.temporaryDirectory
243
- let tmpFile = tmpDir.appendingPathComponent(UUID().uuidString + ".png")
244
-
245
- do {
246
- try FileManager.default.moveItem(at: location, to: tmpFile)
247
- let attachment = try UNNotificationAttachment(
248
- identifier: "\(id)-attachment",
249
- url: tmpFile,
250
- options: nil
251
- )
252
- content.attachments = [attachment]
253
- } catch {
254
- // fall through with no attachment
255
- }
256
- createNotification(id: id, content: content, completion: completion)
257
- }
258
- task.resume()
259
- }
260
-
261
- /// Serializes a ``NavigationAction`` into the JS-bridge shape mirrored by
262
- /// `NavigationAction` in `index.d.ts`. Returns `nil` for `nil` input.
263
- private static func jsonDictionary(from action: NavigationAction?) -> [String: Any]? {
264
- guard let action else { return nil }
265
- switch action {
266
- case .deepLink(let url):
267
- return ["type": "deepLink", "url": url.absoluteString]
268
- case .screen(let name, let data):
269
- var dict: [String: Any] = ["type": "screen", "name": name]
270
- if let data { dict["data"] = data }
271
- return dict
272
- case .richLanding(let url):
273
- return ["type": "richLanding", "url": url.absoluteString]
274
- case .clickAction(let actionString):
275
- return ["type": "clickAction", "action": actionString]
276
- }
277
- }
278
-
279
- private static func bridgeSafePayload(from userInfo: [AnyHashable: Any]) -> [String: Any] {
280
- userInfo.reduce(into: [String: Any]()) { result, pair in
281
- let key = String(describing: pair.key)
282
- let value = pair.value
283
- if let str = value as? String {
284
- result[key] = str
285
- } else if let num = value as? NSNumber {
286
- result[key] = num
287
- } else if let dict = value as? [AnyHashable: Any] {
288
- result[key] = bridgeSafePayload(from: dict)
289
- } else if let arr = value as? [Any] {
290
- result[key] = arr.map { item -> Any in
291
- if let str = item as? String { return str }
292
- if let num = item as? NSNumber { return num }
293
- if let d = item as? [AnyHashable: Any] { return bridgeSafePayload(from: d) }
294
- return "\(item)"
295
- }
296
- } else {
297
- result[key] = "\(value)"
298
- }
299
- }
300
- }
301
- }
@@ -1,3 +0,0 @@
1
- #import <React/RCTBridgeModule.h>
2
- #import <React/RCTEventEmitter.h>
3
- #import <React/RCTViewManager.h>
@@ -1,77 +0,0 @@
1
- //
2
- // AUTO-GENERATED FROM DashXReactNative.swift — DO NOT EDIT.
3
- // Regenerate with `yarn sync-bridge-shim` after editing the Swift file.
4
- //
5
- // The Swift class's @objc method declarations are the source of truth.
6
- // This file mirrors them so old-arch React Native consumers (which discover
7
- // methods via RCT_EXTERN_METHOD) and new-arch consumers (which dispatch via
8
- // the codegen-generated TurboModule spec) both find consistent signatures.
9
- //
10
-
11
- #import <React/RCTBridgeModule.h>
12
- #import <React/RCTEventEmitter.h>
13
-
14
- #ifdef RCT_NEW_ARCH_ENABLED
15
- #import "RNDashXReactNativeSpec.h"
16
- #endif
17
-
18
- @interface RCT_EXTERN_MODULE(DashXReactNative, RCTEventEmitter)
19
-
20
- RCT_EXTERN_METHOD(configure:(NSDictionary *)options);
21
-
22
- RCT_EXTERN_METHOD(identify:(NSDictionary *)options);
23
-
24
- RCT_EXTERN_METHOD(setIdentity:(NSString * _Nullable)uid token:(NSString * _Nullable)token);
25
-
26
- RCT_EXTERN_METHOD(reset);
27
-
28
- RCT_EXTERN_METHOD(track:(NSString *)event data:(NSDictionary * _Nullable)data);
29
-
30
- RCT_EXTERN_METHOD(screen:(NSString *)screenName data:(NSDictionary * _Nullable)data);
31
-
32
- RCT_EXTERN_METHOD(fetchRecord:(NSString *)urn options:(NSDictionary * _Nullable)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
33
-
34
- RCT_EXTERN_METHOD(searchRecords:(NSString *)resource options:(NSDictionary * _Nullable)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
35
-
36
- RCT_EXTERN_METHOD(fetchStoredPreferences:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
37
-
38
- RCT_EXTERN_METHOD(saveStoredPreferences:(NSDictionary *)preferenceData resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
39
-
40
- RCT_EXTERN_METHOD(subscribe);
41
-
42
- RCT_EXTERN_METHOD(unsubscribe:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
43
-
44
- RCT_EXTERN_METHOD(setLogLevel:(double)level);
45
-
46
- RCT_EXTERN_METHOD(uploadAsset:(NSString *)filePath resource:(NSString *)resource attribute:(NSString *)attribute resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
47
-
48
- RCT_EXTERN_METHOD(fetchAsset:(NSString *)assetId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
49
-
50
- RCT_EXTERN_METHOD(enableLifecycleTracking);
51
-
52
- RCT_EXTERN_METHOD(enableAdTracking);
53
-
54
- RCT_EXTERN_METHOD(processURL:(NSString *)url source:(NSString * _Nullable)source forwardToLinkHandler:(BOOL)forwardToLinkHandler);
55
-
56
- RCT_EXTERN_METHOD(trackNotificationNavigation:(NSDictionary * _Nullable)action notificationId:(NSString * _Nullable)notificationId);
57
-
58
- RCT_EXTERN_METHOD(requestNotificationPermission:(BOOL)fallbackToSettings resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
59
-
60
- RCT_EXTERN_METHOD(getNotificationPermissionStatus:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject);
61
-
62
- @end
63
-
64
- #ifdef RCT_NEW_ARCH_ENABLED
65
- @interface DashXReactNative () <NativeDashXReactNativeSpec>
66
- @end
67
-
68
- @implementation DashXReactNative (TurboModule)
69
-
70
- - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
71
- (const facebook::react::ObjCTurboModule::InitParams &)params
72
- {
73
- return std::make_shared<facebook::react::NativeDashXReactNativeSpecJSI>(params);
74
- }
75
-
76
- @end
77
- #endif
@@ -1,244 +0,0 @@
1
- import Foundation
2
- import DashX
3
-
4
- @objc(DashXReactNative)
5
- class DashXReactNative: RCTEventEmitter {
6
- override init() {
7
- super.init()
8
- DashXEventEmitter.instance.registerEventEmitter(eventEmitter: self)
9
- DashX.linkHandler = { url in
10
- DashXEventEmitter.instance.dispatch(name: "linkReceived", body: url.absoluteString)
11
- }
12
- }
13
-
14
- override static func requiresMainQueueSetup() -> Bool {
15
- return true
16
- }
17
-
18
- override func supportedEvents() -> [String] {
19
- return ["messageReceived", "linkReceived", "notificationClicked"]
20
- }
21
-
22
- @objc(configure:)
23
- func configure(_ options: NSDictionary) {
24
- guard let publicKey = options["publicKey"] as? String, !publicKey.isEmpty else {
25
- return
26
- }
27
- let baseURI = options["baseURI"] as? String
28
- let targetEnvironment = options["targetEnvironment"] as? String
29
-
30
- DashX.configure(
31
- withPublicKey: publicKey,
32
- baseURI: baseURI,
33
- targetEnvironment: targetEnvironment
34
- )
35
- }
36
-
37
- @objc(identify:)
38
- func identify(_ options: NSDictionary) {
39
- let stringOptions = (options as? [String: Any])?.compactMapValues { ($0 as? CustomStringConvertible)?.description } ?? [:]
40
- try? DashX.identify(options: stringOptions)
41
- }
42
-
43
- @objc(setIdentity:token:)
44
- func setIdentity(_ uid: NSString?, _ token: NSString?) {
45
- DashX.setIdentity(uid: uid as String?, token: token as String?)
46
- }
47
-
48
- @objc
49
- func reset() {
50
- DashX.reset()
51
- }
52
-
53
- @objc(track:data:)
54
- func track(_ event: String, _ data: NSDictionary?) {
55
- DashX.track(event, withData: data as? [String: Any])
56
- }
57
-
58
- @objc(screen:data:)
59
- func screen(_ screenName: String, _ data: NSDictionary?) {
60
- DashX.screen(screenName, withData: data as? [String: Any])
61
- }
62
-
63
- @objc(fetchRecord:options:resolve:reject:)
64
- func fetchRecord(_ urn: String, options: NSDictionary?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
65
- DashXClient.instance.fetchRecord(
66
- urn: urn,
67
- preview: options?["preview"] as? Bool,
68
- language: options?["language"] as? String,
69
- fields: options?["fields"] as? [[String: Any]],
70
- include: options?["include"] as? [[String: Any]],
71
- exclude: options?["exclude"] as? [[String: Any]]
72
- ) { result in
73
- switch result {
74
- case .success(let record): resolve(record)
75
- case .failure(let error): reject("EUNSPECIFIED", error.localizedDescription, error)
76
- }
77
- }
78
- }
79
-
80
- @objc(searchRecords:options:resolve:reject:)
81
- func searchRecords(_ resource: String, options: NSDictionary?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
82
- DashXClient.instance.searchRecords(
83
- resource: resource,
84
- filter: options?["filter"] as? [String: Any],
85
- order: options?["order"] as? [[String: Any]],
86
- limit: options?["limit"] as? Int,
87
- page: options?["page"] as? Int,
88
- preview: options?["preview"] as? Bool,
89
- language: options?["language"] as? String,
90
- fields: options?["fields"] as? [[String: Any]],
91
- include: options?["include"] as? [[String: Any]],
92
- exclude: options?["exclude"] as? [[String: Any]]
93
- ) { result in
94
- switch result {
95
- case .success(let records): resolve(records)
96
- case .failure(let error): reject("EUNSPECIFIED", error.localizedDescription, error)
97
- }
98
- }
99
- }
100
-
101
- @objc(fetchStoredPreferences:reject:)
102
- func fetchStoredPreferences(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
103
- DashXClient.instance.fetchStoredPreferences { result in
104
- switch result {
105
- case .success(let prefs): resolve(prefs)
106
- case .failure(let error): reject("EUNSPECIFIED", error.localizedDescription, error)
107
- }
108
- }
109
- }
110
-
111
- @objc(saveStoredPreferences:resolve:reject:)
112
- func saveStoredPreferences(_ preferenceData: NSDictionary, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
113
- guard let dict = preferenceData as? [String: Any] else {
114
- reject("EINVAL", "preferenceData must be a plain object", nil)
115
- return
116
- }
117
- DashXClient.instance.saveStoredPreferences(preferenceData: dict) { result in
118
- switch result {
119
- case .success(let success): resolve(success)
120
- case .failure(let error): reject("EUNSPECIFIED", error.localizedDescription, error)
121
- }
122
- }
123
- }
124
-
125
- @objc
126
- func subscribe() {
127
- DashX.subscribe()
128
- }
129
-
130
- @objc(unsubscribe:reject:)
131
- func unsubscribe(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
132
- DashX.unsubscribe { result in
133
- switch result {
134
- case .success(let didUnsubscribe):
135
- resolve(["success": didUnsubscribe])
136
- case .failure(let error):
137
- reject("EUNSPECIFIED", error.localizedDescription, error)
138
- }
139
- }
140
- }
141
-
142
- @objc(setLogLevel:)
143
- func setLogLevel(_ level: Double) {
144
- // JS contract: 0 = off, 1 = errors, 2 = debug
145
- // Native SDK: off = -1, error = 0, info = 1, debug = 2
146
- let logLevel: DashXLog.LogLevel
147
- switch Int(level) {
148
- case 0: logLevel = .off
149
- case 1: logLevel = .error
150
- case 2: logLevel = .debug
151
- default: logLevel = .off
152
- }
153
- DashXLog.setLogLevel(to: logLevel)
154
- }
155
-
156
- @objc(uploadAsset:resource:attribute:resolve:reject:)
157
- func uploadAsset(_ filePath: String, resource: String, attribute: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
158
- let fileURL = URL(fileURLWithPath: filePath)
159
- DashXClient.instance.uploadAsset(fileURL: fileURL, resource: resource, attribute: attribute) { result in
160
- switch result {
161
- case .success(let assetResponse):
162
- if let data = try? JSONEncoder().encode(assetResponse),
163
- let dict = try? JSONSerialization.jsonObject(with: data) as? NSDictionary {
164
- resolve(dict)
165
- } else {
166
- resolve(nil)
167
- }
168
- case .failure(let error):
169
- reject("EUNSPECIFIED", error.localizedDescription, error)
170
- }
171
- }
172
- }
173
-
174
- @objc(fetchAsset:resolve:reject:)
175
- func fetchAsset(_ assetId: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
176
- DashXClient.instance.fetchAsset(assetId: assetId) { result in
177
- switch result {
178
- case .success(let assetResponse):
179
- if let data = try? JSONEncoder().encode(assetResponse),
180
- let dict = try? JSONSerialization.jsonObject(with: data) as? NSDictionary {
181
- resolve(dict)
182
- } else {
183
- resolve(nil)
184
- }
185
- case .failure(let error):
186
- reject("EUNSPECIFIED", error.localizedDescription, error)
187
- }
188
- }
189
- }
190
-
191
- @objc
192
- func enableLifecycleTracking() {
193
- DispatchQueue.main.async { DashX.enableLifecycleTracking() }
194
- }
195
-
196
- @objc
197
- func enableAdTracking() {
198
- DashX.enableAdTracking()
199
- }
200
-
201
- @objc(processURL:source:forwardToLinkHandler:)
202
- func processURL(_ url: String, source: NSString?, forwardToLinkHandler: Bool) {
203
- guard let parsedURL = URL(string: url) else { return }
204
- DashX.processURL(parsedURL, source: source as String?, forwardToLinkHandler: forwardToLinkHandler)
205
- }
206
-
207
- @objc(trackNotificationNavigation:notificationId:)
208
- func trackNotificationNavigation(_ action: NSDictionary?, notificationId: NSString?) {
209
- var navigationAction: NavigationAction? = nil
210
- if let action = action, let type = action["type"] as? String {
211
- switch type {
212
- case "deepLink":
213
- if let urlString = action["url"] as? String, let url = URL(string: urlString) {
214
- navigationAction = .deepLink(url: url)
215
- }
216
- case "screen":
217
- if let name = action["name"] as? String {
218
- navigationAction = .screen(name: name, data: action["data"] as? [String: String])
219
- }
220
- case "richLanding":
221
- if let urlString = action["url"] as? String, let url = URL(string: urlString) {
222
- navigationAction = .richLanding(url: url)
223
- }
224
- case "clickAction":
225
- if let actionStr = action["action"] as? String {
226
- navigationAction = .clickAction(action: actionStr)
227
- }
228
- default:
229
- break
230
- }
231
- }
232
- DashX.trackNotificationNavigation(navigationAction, notificationId: notificationId as String?)
233
- }
234
-
235
- @objc(requestNotificationPermission:resolve:reject:)
236
- func requestNotificationPermission(_ fallbackToSettings: Bool, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
237
- DashX.requestNotificationPermission(fallbackToSettings: fallbackToSettings) { status in resolve(status.rawValue) }
238
- }
239
-
240
- @objc(getNotificationPermissionStatus:reject:)
241
- func getNotificationPermissionStatus(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
242
- DashX.getNotificationPermissionStatus { status in resolve(status.rawValue) }
243
- }
244
- }