@infilectorg/infiviz-shots-react-sdk 1.0.51 → 1.0.53

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 (50) hide show
  1. package/android/build.gradle +1 -1
  2. package/ios/InfivizShotSDK.xcframework/Info.plist +5 -5
  3. package/ios/InfivizShotSDK.xcframework/ios-arm64/InfivizShotSDK.framework/Assets.car +0 -0
  4. package/ios/InfivizShotSDK.xcframework/ios-arm64/InfivizShotSDK.framework/InfivizShotSDK +0 -0
  5. package/ios/InfivizShotSDK.xcframework/ios-arm64/InfivizShotSDK.framework/Modules/InfivizShotSDK.swiftmodule/arm64-apple-ios.abi.json +77 -77
  6. package/ios/InfivizShotSDK.xcframework/ios-arm64/InfivizShotSDK.framework/Modules/InfivizShotSDK.swiftmodule/arm64-apple-ios.swiftmodule +0 -0
  7. package/ios/InfivizShotSDK.xcframework/ios-arm64/InfivizShotSDK.framework/shotsSDK.storyboardc/xUL-ol-gRQ-view-6A8-mO-Rhi.nib +0 -0
  8. package/ios/InfivizShotSDK.xcframework/ios-arm64_x86_64-simulator/InfivizShotSDK.framework/Assets.car +0 -0
  9. package/ios/InfivizShotSDK.xcframework/ios-arm64_x86_64-simulator/InfivizShotSDK.framework/InfivizShotSDK +0 -0
  10. package/ios/InfivizShotSDK.xcframework/ios-arm64_x86_64-simulator/InfivizShotSDK.framework/Modules/InfivizShotSDK.swiftmodule/arm64-apple-ios-simulator.abi.json +77 -77
  11. package/ios/InfivizShotSDK.xcframework/ios-arm64_x86_64-simulator/InfivizShotSDK.framework/Modules/InfivizShotSDK.swiftmodule/arm64-apple-ios-simulator.swiftmodule +0 -0
  12. package/ios/InfivizShotSDK.xcframework/ios-arm64_x86_64-simulator/InfivizShotSDK.framework/Modules/InfivizShotSDK.swiftmodule/x86_64-apple-ios-simulator.abi.json +77 -77
  13. package/ios/InfivizShotSDK.xcframework/ios-arm64_x86_64-simulator/InfivizShotSDK.framework/Modules/InfivizShotSDK.swiftmodule/x86_64-apple-ios-simulator.swiftmodule +0 -0
  14. package/ios/InfivizShotSDK.xcframework/ios-arm64_x86_64-simulator/InfivizShotSDK.framework/shotsSDK.storyboardc/xUL-ol-gRQ-view-6A8-mO-Rhi.nib +0 -0
  15. package/ios/InfivizShotsReactSdk.swift +564 -590
  16. package/lib/module/NativeInfivizShotsReactSdk.js +2 -0
  17. package/lib/module/NativeInfivizShotsReactSdk.js.map +1 -1
  18. package/lib/module/index.js +4 -2
  19. package/lib/module/index.js.map +1 -1
  20. package/lib/module/package.json +1 -0
  21. package/lib/module/types/Environment.js +2 -0
  22. package/lib/module/types/Environment.js.map +1 -1
  23. package/lib/module/types/ImageMetaData.js +2 -0
  24. package/lib/module/types/ImageMetaData.js.map +1 -1
  25. package/lib/module/types/InfiSession.js +2 -0
  26. package/lib/module/types/InfiSession.js.map +1 -1
  27. package/lib/module/types/LabelScore.js +1 -1
  28. package/lib/module/types/LabelScore.js.map +1 -1
  29. package/lib/module/types/SessionStatus.js +1 -1
  30. package/lib/module/types/SessionStatus.js.map +1 -1
  31. package/lib/module/types/SessionSyncStateEnum.js +2 -0
  32. package/lib/module/types/SessionSyncStateEnum.js.map +1 -1
  33. package/lib/typescript/package.json +1 -0
  34. package/lib/typescript/src/NativeInfivizShotsReactSdk.d.ts +23 -0
  35. package/lib/typescript/src/NativeInfivizShotsReactSdk.d.ts.map +1 -0
  36. package/lib/typescript/src/index.d.ts +24 -0
  37. package/lib/typescript/src/index.d.ts.map +1 -0
  38. package/lib/typescript/src/types/Environment.d.ts +5 -0
  39. package/lib/typescript/src/types/Environment.d.ts.map +1 -0
  40. package/lib/typescript/src/types/ImageMetaData.d.ts +13 -0
  41. package/lib/typescript/src/types/ImageMetaData.d.ts.map +1 -0
  42. package/lib/typescript/src/types/InfiSession.d.ts +18 -0
  43. package/lib/typescript/src/types/InfiSession.d.ts.map +1 -0
  44. package/lib/typescript/src/types/LabelScore.d.ts +5 -0
  45. package/lib/typescript/src/types/LabelScore.d.ts.map +1 -0
  46. package/lib/typescript/src/types/SessionStatus.d.ts +5 -0
  47. package/lib/typescript/src/types/SessionStatus.d.ts.map +1 -0
  48. package/lib/typescript/src/types/SessionSyncStateEnum.d.ts +8 -0
  49. package/lib/typescript/src/types/SessionSyncStateEnum.d.ts.map +1 -0
  50. package/package.json +1 -1
@@ -12,339 +12,313 @@ import React
12
12
 
13
13
  @objc(InfivizShotsReactSdk)
14
14
  class InfivizShotsReactSdk: RCTEventEmitter {
15
- @objc
16
- override static func moduleName() -> String! {
17
- return "InfivizShotsReactSdk"
18
- }
19
-
20
- @objc
21
- override static func requiresMainQueueSetup() -> Bool {
22
- return false
23
- }
24
-
25
- // MARK: – RCTEventEmitter Boilerplate
26
-
27
- private var hasListeners = false
28
-
29
- // 3. List of events that JS can subscribe to:
30
- override func supportedEvents() -> [String]! {
31
- return [
32
- "SyncEvent",
33
- "ActionsGeneratedEvent",
34
- "SessionRealTimeResultEvent"]
35
- }
36
-
37
- // 4. Only send events if JS has at least one listener:
38
- override func startObserving() {
39
- hasListeners = true
40
-
41
- NotificationCenter.default.addObserver(self,
42
- selector: #selector(handleActionsGeneratedEvent(_:)),
43
- name: NSNotification.Name("ActionsGeneratedEvent"),
44
- object: nil)
15
+ @objc
16
+ override static func moduleName() -> String! {
17
+ return "InfivizShotsReactSdk"
18
+ }
19
+
20
+ @objc
21
+ override static func requiresMainQueueSetup() -> Bool {
22
+ return false
23
+ }
24
+
25
+ // MARK: – RCTEventEmitter Boilerplate
26
+
27
+ private var hasListeners = false
28
+
29
+ // 3. List of events that JS can subscribe to:
30
+ override func supportedEvents() -> [String]! {
31
+ return [
32
+ "SyncEvent",
33
+ "ActionsGeneratedEvent",
34
+ "SessionRealTimeResultEvent"]
35
+ }
36
+
37
+ // 4. Only send events if JS has at least one listener:
38
+ override func startObserving() {
39
+ hasListeners = true
40
+
45
41
  NotificationCenter.default.addObserver(self,
46
- selector: #selector(handleSessionRealTimeResultEvent(_:)),
47
- name: NSNotification.Name("SessionRealTimeResultEvent"),
48
- object: nil)
49
-
50
- }
51
-
52
- override func stopObserving() {
53
- hasListeners = false
54
- NotificationCenter.default.removeObserver(self, name: NSNotification.Name("ActionsGeneratedEvent"), object: nil)
55
- NotificationCenter.default.removeObserver(self, name: NSNotification.Name("SessionRealTimeResultEvent"), object: nil)
56
- }
57
-
58
- // 5. If you have no constants to export, just return empty:
59
- override func constantsToExport() -> [AnyHashable: Any]! {
60
- return [:]
61
- }
62
-
63
-
64
- var activity: InfivizShotsActivity?
65
-
66
- // MARK: –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
67
- // MARK: – Helper Methods (not directly exposed to JS)
68
-
69
-
70
- // MARK: - Universal Session ID
71
- @objc
72
- func fetchUniversalSessionId(_ tempID: NSString, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
73
- InfivizShotsSDK.shared.fetchUniversalSessionId(temporarySessionID: tempID as String, completion: { sessionID, error in
74
- if let id = sessionID {
75
- resolve(id)
76
- } else {
77
- reject("FETCH_SESSION_ID_ERROR", "Session not found", nil)
78
- }
79
- })
80
- }
81
-
82
- @objc
83
- func syncSession(_ sessionId: NSString) {
84
- // Kick off the upload. No resolver/rejecter—just emit events once it’s done.
85
- InfivizShotsSDK.shared.uploadSession(temporarySessionID: sessionId as String) { result in
86
- switch result {
87
- case .success(let response):
88
- if self.hasListeners {
89
- let payload: [String: Any] = [
90
- "status": "200",
91
- "universalSessionID": response,
92
- "temporarySessionID": sessionId as String
93
- ]
94
- self.sendEvent(withName: "SyncEvent", body: payload)
95
- }
96
- case .failure(let error):
97
- if self.hasListeners {
98
- let payload: [String: Any] = [
99
- "status": "400",
100
- "message": error.localizedDescription,
101
- "temporarySessionID": sessionId as String
102
- ]
103
- self.sendEvent(withName: "SyncEvent", body: payload)
104
- }
105
- }
106
- }
107
- }
108
-
109
- // MARK: - Sync Multiple Sessions
110
- /// Bridge to InfivizShotsSDK.shared.syncSessions(temporarySessionIDs:completionHandler:)
111
-
112
- @objc
113
- func uploadSession(temporarySessionIDs: NSArray) {
42
+ selector: #selector(handleActionsGeneratedEvent(_:)),
43
+ name: NSNotification.Name("ActionsGeneratedEvent"),
44
+ object: nil)
45
+ NotificationCenter.default.addObserver(self,
46
+ selector: #selector(handleSessionRealTimeResultEvent(_:)),
47
+ name: NSNotification.Name("SessionRealTimeResultEvent"),
48
+ object: nil)
49
+
50
+ }
51
+
52
+ override func stopObserving() {
53
+ hasListeners = false
54
+ NotificationCenter.default.removeObserver(self, name: NSNotification.Name("ActionsGeneratedEvent"), object: nil)
55
+ NotificationCenter.default.removeObserver(self, name: NSNotification.Name("SessionRealTimeResultEvent"), object: nil)
56
+ }
57
+
58
+ // 5. If you have no constants to export, just return empty:
59
+ override func constantsToExport() -> [AnyHashable: Any]! {
60
+ return [:]
61
+ }
62
+
63
+
64
+ var activity: InfivizShotsActivity?
65
+
66
+ // MARK: –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
67
+ // MARK: – Helper Methods (not directly exposed to JS)
68
+
69
+
70
+ // MARK: - Universal Session ID
71
+ @objc
72
+ func fetchUniversalSessionId(_ tempID: NSString, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
73
+ InfivizShotsSDK.shared.fetchUniversalSessionId(temporarySessionID: tempID as String, completion: { sessionID, error in
74
+ if let id = sessionID {
75
+ resolve(id)
76
+ } else {
77
+ reject("FETCH_SESSION_ID_ERROR", "Session not found", nil)
78
+ }
79
+ })
80
+ }
81
+
82
+ @objc
83
+ func syncSession(_ sessionId: NSString) {
84
+ // Kick off the upload. No resolver/rejecter—just emit events once it’s done.
85
+ InfivizShotsSDK.shared.uploadSession(temporarySessionID: sessionId as String) { result in
86
+ switch result {
87
+ case .success(let response):
88
+ if self.hasListeners {
89
+ let payload: [String: Any] = [
90
+ "status": "200",
91
+ "universalSessionID": response,
92
+ "temporarySessionID": sessionId as String
93
+ ]
94
+ self.sendEvent(withName: "SyncEvent", body: payload)
95
+ }
96
+ case .failure(let error):
97
+ if self.hasListeners {
98
+ let payload: [String: Any] = [
99
+ "status": "400",
100
+ "message": error.localizedDescription,
101
+ "temporarySessionID": sessionId as String
102
+ ]
103
+ self.sendEvent(withName: "SyncEvent", body: payload)
104
+ }
105
+ }
106
+ }
107
+ }
108
+
109
+ // MARK: - Sync Multiple Sessions
110
+ /// Bridge to InfivizShotsSDK.shared.syncSessions(temporarySessionIDs:completionHandler:)
111
+
112
+ @objc
113
+ func uploadSession(temporarySessionIDs: NSArray) {
114
114
  var ids: [String] = []
115
115
  if let arr = temporarySessionIDs as? [String] {
116
- ids = arr
116
+ ids = arr
117
117
  } else if let arr = temporarySessionIDs as? [NSString] {
118
- ids = arr.map { $0 as String }
118
+ ids = arr.map { $0 as String }
119
119
  }
120
-
120
+
121
121
  guard !ids.isEmpty else { return }
122
-
122
+
123
123
  InfivizShotsSDK.shared.syncSessions(temporarySessionIDs: ids) { sessionId, result in
124
- switch result {
125
- case .success(let message):
126
- if self.hasListeners {
127
- let payload: [String: Any] = [
128
- "status": "200",
129
- "universalSessionID": message,
130
- "temporarySessionID": sessionId
131
- ]
132
- self.sendEvent(withName: "SyncEvent", body: payload)
133
- }
134
- case .failure(let error):
135
- if self.hasListeners {
136
- let payload: [String: Any] = [
137
- "status": "400",
138
- "universalSessionID": error,
139
- "temporarySessionID": sessionId
140
- ]
141
- self.sendEvent(withName: "SyncEvent", body: payload)
142
- }
124
+ switch result {
125
+ case .success(let message):
126
+ if self.hasListeners {
127
+ let payload: [String: Any] = [
128
+ "status": "200",
129
+ "universalSessionID": message,
130
+ "temporarySessionID": sessionId
131
+ ]
132
+ self.sendEvent(withName: "SyncEvent", body: payload)
143
133
  }
134
+ case .failure(let error):
135
+ if self.hasListeners {
136
+ let payload: [String: Any] = [
137
+ "status": "400",
138
+ "universalSessionID": error,
139
+ "temporarySessionID": sessionId
140
+ ]
141
+ self.sendEvent(withName: "SyncEvent", body: payload)
142
+ }
143
+ }
144
144
  }
145
- }
146
-
147
- // MARK: - Get Session Result
148
-
145
+ }
146
+
147
+ // MARK: - Get Session Result
148
+
149
149
  @objc
150
150
  func getSessionStatus(
151
- _ temporarySessionID: NSString,
152
- resolver resolve: @escaping RCTPromiseResolveBlock,
153
- rejecter reject: @escaping RCTPromiseRejectBlock
151
+ _ temporarySessionID: NSString,
152
+ resolver resolve: @escaping RCTPromiseResolveBlock,
153
+ rejecter reject: @escaping RCTPromiseRejectBlock
154
154
  ) {
155
- InfivizShotsSDK.shared.checkState(sessionID: temporarySessionID as String) { result in
156
- switch result {
157
- case .success(let response):
158
- let json = ["sessionId": temporarySessionID,
159
- "status": response]
160
-
161
- if let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []) {
162
- let jsonString = String(data: jsonData, encoding: .utf8)
163
- resolve(jsonString)
164
- }
165
-
166
- case .failure(let error):
167
- reject(
168
- "RESULT_FAILED",
169
- "Failed to get result for \(temporarySessionID): \(error.localizedDescription)",
170
- nil
171
- )
172
- }
173
- }
174
- }
175
-
176
- // MARK: - Sync All Data
177
- @objc
178
- func syncAllData(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
179
- InfivizShotsSDK.shared.syncAllData { result in
180
- switch result {
181
- case .success(let message):
182
- resolve(message)
183
- case .failure(let error):
184
- reject("SYNC_FAILED", "Sync failed: \(error)", nil)
185
- }
186
- }
187
- }
188
-
189
- // MARK: - Fetch Session Details
190
- @objc
191
- func fetchSessionDetails(_ temporarySessionID: NSString, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
192
- InfivizShotsSDK.shared.fetchSessionDetails(temporarySessionID: temporarySessionID as String) { result in
193
- switch result {
194
- case .success(let value):
195
- // Convert any value to a clean dictionary that handles Optionals properly
196
- let cleanDict = self.convertToCleanDictionary(value)
197
- print(value)
198
- // Return the dictionary directly instead of JSON string
199
- resolve(cleanDict)
200
- case .failure(let error):
201
- reject("RESULT_FAILED", "Failed to get result: \(error)", nil)
202
- }
203
- }
204
- }
205
-
206
- // MARK: - Convert Any to Clean Dictionary
207
- private func convertToCleanDictionary(_ value: Any) -> [String: Any] {
208
- if let dict = value as? [String: Any] {
209
- return cleanDictionary(dict)
210
- } else {
211
- let mirror = Mirror(reflecting: value)
212
- var result: [String: Any] = [:]
213
-
214
- for child in mirror.children {
215
- if let label = child.label {
216
- result[label] = unwrapOptional(child.value)
217
- }
218
- }
219
- return result
220
- }
221
- }
222
-
223
- // MARK: - Recursively Clean Dictionary
224
- private func cleanDictionary(_ dict: [String: Any]) -> [String: Any] {
225
- var cleaned: [String: Any] = [:]
226
- for (key, value) in dict {
227
- cleaned[key] = unwrapOptional(value)
228
- }
229
- return cleaned
230
- }
231
-
232
- // MARK: - Unwrap Optionals and Flatten SDK Values
233
- private func unwrapOptional(_ value: Any) -> Any {
234
- // 1. Handle Optional
235
- let mirror = Mirror(reflecting: value)
236
- if mirror.displayStyle == .optional {
237
- if let unwrapped = mirror.children.first?.value {
238
- return unwrapOptional(unwrapped)
239
- } else {
240
- return NSNull()
241
- }
242
- }
155
+ InfivizShotsSDK.shared.checkState(sessionID: temporarySessionID as String) { result in
156
+ switch result {
157
+ case .success(let response):
158
+ let json = ["sessionId": temporarySessionID,
159
+ "status": response]
243
160
 
244
- // 2. Handle JSONValue directly
245
- if let jsonValue = value as? InfivizShotSDK.JSONValue {
246
- switch jsonValue {
247
- case .string(let str): return str
248
- case .bool(let b): return b
249
- case .int(let i): return i
250
- case .double(let d): return d
251
- case .dictionary(let dict):
252
- var cleaned: [String: Any] = [:]
253
- for (k, v) in dict {
254
- cleaned[k] = unwrapOptional(v)
255
- }
256
- return cleaned
257
- case .array(let arr):
258
- return arr.map { unwrapOptional($0) }
259
- case .null:
260
- return NSNull()
261
- @unknown default:
262
- return NSNull()
161
+ if let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []) {
162
+ let jsonString = String(data: jsonData, encoding: .utf8)
163
+ resolve(jsonString)
263
164
  }
264
- }
265
165
 
266
- // 3. Arrays
267
- if let array = value as? [Any] {
268
- return array.map { unwrapOptional($0) }
166
+ case .failure(let error):
167
+ reject(
168
+ "RESULT_FAILED",
169
+ "Failed to get result for \(temporarySessionID): \(error.localizedDescription)",
170
+ nil
171
+ )
269
172
  }
173
+ }
174
+ }
270
175
 
271
- // 4. Dictionaries
272
- if let dict = value as? [String: Any] {
273
- var cleaned: [String: Any] = [:]
274
- for (k, v) in dict {
275
- cleaned[k] = unwrapOptional(v)
276
- }
277
- return cleaned
278
- }
176
+ // MARK: - Sync All Data
177
+ @objc
178
+ func syncAllData(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
179
+ InfivizShotsSDK.shared.syncAllData { result in
180
+ switch result {
181
+ case .success(let message):
182
+ resolve(message)
183
+ case .failure(let error):
184
+ reject("SYNC_FAILED", "Sync failed: \(error)", nil)
185
+ }
186
+ }
187
+ }
279
188
 
280
- // 5. Enum like SessionSyncStateEnum
281
- let typeName = String(describing: type(of: value))
282
- if typeName.contains("InfivizShotSDK.SessionSyncStateEnum") {
283
- return String(describing: value)
284
- }
189
+ // MARK: - Fetch Session Details
190
+ @objc
191
+ func fetchSessionDetails(_ temporarySessionID: NSString, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
192
+ InfivizShotsSDK.shared.fetchSessionDetails(temporarySessionID: temporarySessionID as String) { result in
193
+ switch result {
194
+ case .success(let value):
195
+ // Convert any value to a clean dictionary that handles Optionals properly
196
+ let cleanDict = self.convertToCleanDictionary(value)
197
+ // Return the dictionary directly instead of JSON string
198
+ resolve(cleanDict)
199
+ case .failure(let error):
200
+ reject("RESULT_FAILED", "Failed to get result: \(error)", nil)
201
+ }
202
+ }
203
+ }
204
+
205
+ // Helper method to convert any value to a clean dictionary that handles Optionals
206
+ private func convertToCleanDictionary(_ value: Any) -> [String: Any] {
207
+ if let dict = value as? [String: Any] {
208
+ return cleanDictionary(dict)
209
+ } else {
210
+ // Try to convert to dictionary using Mirror reflection
211
+ let mirror = Mirror(reflecting: value)
212
+ var result: [String: Any] = [:]
213
+
214
+ for child in mirror.children {
215
+ if let label = child.label {
216
+ result[label] = unwrapOptional(child.value)
217
+ }
218
+ }
219
+ return result
220
+ }
221
+ }
222
+
223
+ // Recursively clean a dictionary to handle Optionals
224
+ private func cleanDictionary(_ dict: [String: Any]) -> [String: Any] {
225
+ var cleaned: [String: Any] = [:]
226
+
227
+ for (key, value) in dict {
228
+ cleaned[key] = unwrapOptional(value)
229
+ }
230
+
231
+ return cleaned
232
+ }
233
+
234
+ // Unwrap Optional values and clean nested structures
235
+ private func unwrapOptional(_ value: Any) -> Any {
236
+ let mirror = Mirror(reflecting: value)
237
+
238
+ // Check if it's an Optional by checking the type name
239
+ let typeName = String(describing: type(of: value))
240
+ if typeName.hasPrefix("Optional<") {
241
+ if let unwrapped = mirror.children.first?.value {
242
+ return unwrapOptional(unwrapped)
243
+ } else {
244
+ return NSNull() // nil value
245
+ }
246
+ }
247
+
248
+ // Handle arrays
249
+ if let array = value as? [Any] {
250
+ return array.map { unwrapOptional($0) }
251
+ }
252
+
253
+ // Handle dictionaries
254
+ if let dict = value as? [String: Any] {
255
+ return cleanDictionary(dict)
256
+ }
257
+
258
+ // Handle Date objects
259
+ if let date = value as? Date {
260
+ let formatter = DateFormatter()
261
+ formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
262
+ return formatter.string(from: date)
263
+ }
264
+
265
+ // Handle custom objects (like ImageMetaData) using Mirror reflection
266
+ // This ensures that objects with optional properties are properly serialized
267
+ let objectMirror = Mirror(reflecting: value)
268
+ if !objectMirror.children.isEmpty {
269
+ var result: [String: Any] = [:]
270
+ for child in objectMirror.children {
271
+ if let label = child.label {
272
+ result[label] = unwrapOptional(child.value)
273
+ }
274
+ }
275
+ return result
276
+ }
277
+
278
+ // Return the value as-is if it's a basic type
279
+ return value
280
+ }
285
281
 
286
- // 6. Date
287
- if let date = value as? Date {
288
- let formatter = DateFormatter()
289
- formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
290
- return formatter.string(from: date)
291
- }
282
+ // MARK: - Logout
283
+ @objc
284
+ func logout(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
285
+ InfivizShotsSDK.shared.callLogoutAPI { result in
286
+ switch result {
287
+ case .success(let success):
288
+ resolve(success)
289
+ case .failure(let error):
290
+ reject("LOGOUT_FAILED", "Logout error: \(error)", nil)
291
+ }
292
+ }
293
+ }
292
294
 
293
- // 7. Custom objects
294
- if !mirror.children.isEmpty {
295
- var result: [String: Any] = [:]
296
- for child in mirror.children {
297
- if let label = child.label {
298
- result[label] = unwrapOptional(child.value)
299
- }
300
- }
301
- return result
302
- }
295
+ // MARK: - Reprocessing Enable Time
296
+ @objc
297
+ func getReprocessingButtonEnableTime(_ sessionID: NSString, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
298
+ InfivizShotsSDK.shared.getReprocessingButtonEnableTime(sessionID: sessionID as String) { result in
299
+ switch result {
300
+ case .success(let time):
301
+ resolve(time)
302
+ case .failure(let error):
303
+ reject("REPROCESS_TIME_ERROR", "Error fetching reprocessing time: \(error)", nil)
304
+ }
305
+ }
306
+ }
303
307
 
304
- // 8. Primitive
305
- return value
306
- }
308
+ // MARK: - Start Reprocessing Workflow
309
+ @objc
310
+ func startReprocessingWorkflow(_ sessionID: NSString, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
311
+ InfivizShotsSDK.shared.startReprocessingWorkflow(sessionID: sessionID as String) { result in
312
+ switch result {
313
+ case .success(let time):
314
+ resolve(time)
315
+ case .failure(let error):
316
+ reject("REPROCESS_WORKFLOW_ERROR", "Reprocessing workflow error: \(error)", nil)
317
+ }
318
+ }
319
+ }
307
320
 
308
- // MARK: - Logout
309
- @objc
310
- func logout(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
311
- InfivizShotsSDK.shared.callLogoutAPI { result in
312
- switch result {
313
- case .success(let success):
314
- resolve(success)
315
- case .failure(let error):
316
- reject("LOGOUT_FAILED", "Logout error: \(error)", nil)
317
- }
318
- }
319
- }
320
-
321
- // MARK: - Reprocessing Enable Time
322
- @objc
323
- func getReprocessingButtonEnableTime(_ sessionID: NSString, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
324
- InfivizShotsSDK.shared.getReprocessingButtonEnableTime(sessionID: sessionID as String) { result in
325
- switch result {
326
- case .success(let time):
327
- resolve(time)
328
- case .failure(let error):
329
- reject("REPROCESS_TIME_ERROR", "Error fetching reprocessing time: \(error)", nil)
330
- }
331
- }
332
- }
333
-
334
- // MARK: - Start Reprocessing Workflow
335
- @objc
336
- func startReprocessingWorkflow(_ sessionID: NSString, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
337
- InfivizShotsSDK.shared.startReprocessingWorkflow(sessionID: sessionID as String) { result in
338
- switch result {
339
- case .success(let time):
340
- resolve(time)
341
- case .failure(let error):
342
- reject("REPROCESS_WORKFLOW_ERROR", "Reprocessing workflow error: \(error)", nil)
343
- }
344
- }
345
- }
346
-
347
- // MARK: - Start Camera
321
+ // MARK: - Start Camera
348
322
  @objc(startCamera:storeTitle:storeId:photoType:category:maxPhoto:maxPhotoOneGo:metaData:resolver:rejecter:)
349
323
  func startCamera(_ taskName: NSString,
350
324
  storeTitle: NSString,
@@ -356,229 +330,229 @@ class InfivizShotsReactSdk: RCTEventEmitter {
356
330
  metaData: NSDictionary,
357
331
  resolver resolve: @escaping RCTPromiseResolveBlock,
358
332
  rejecter reject: @escaping RCTPromiseRejectBlock) {
359
-
360
- DispatchQueue.main.async {
361
- // 1️⃣ Build the CameraContext just like before
362
- let metadataDict: [String: Any]? = metaData as? [String: Any]
363
- let context = CameraContext(
364
- taskName: taskName as String,
365
- storeTitle: storeTitle as String,
366
- storeId: storeId as String,
367
- photoType: photoType as String,
368
- category: category as String,
369
- maxPhoto: maxPhoto.intValue,
370
- maxPhotoOneGo: maxPhotoOneGo.intValue,
371
- tempSessionId: nil,
372
- imageURI: nil,
373
- navigationController: nil,
374
- retake: false,
375
- metaData: metadataDict
376
- )
377
-
378
- // 2️⃣ Instantiate the SDK activity
379
- let activity = InfilectSDKCameraActivityForResult(cameraContext: context)
380
-
381
- // 3️⃣ Call its existing `start(completion:)` which will handle validation,
382
- activity.start { result in
383
- switch result {
384
- case .success(let sessionID):
385
- resolve(sessionID)
386
- case .failure(let apiError):
387
- reject("CAMERA_ERROR", apiError.localizedDescription, nil)
388
- }
389
- }
390
- }
391
- }
392
-
393
- @objc
394
- func initialize(_ appID: NSString,
395
- authSecret: NSString,
396
- accountKey: NSString,
397
- userID: NSString,
398
- clientID: NSString,
399
- apiToken: NSString,
400
- env: NSString,
401
- resolver resolve: @escaping RCTPromiseResolveBlock,
402
- rejecter reject: @escaping RCTPromiseRejectBlock) {
403
-
404
- let model = InfivizUserLoginContext(
405
- appID: appID as String,
406
- authSecret: authSecret as String,
407
- accountKey: accountKey as String,
408
- userID: userID as String,
409
- clientID: clientID as String,
410
- apiToken: apiToken as String
333
+
334
+ DispatchQueue.main.async {
335
+ // 1️⃣ Build the CameraContext just like before
336
+ let metadataDict: [String: Any]? = metaData as? [String: Any]
337
+ let context = CameraContext(
338
+ taskName: taskName as String,
339
+ storeTitle: storeTitle as String,
340
+ storeId: storeId as String,
341
+ photoType: photoType as String,
342
+ category: category as String,
343
+ maxPhoto: maxPhoto.intValue,
344
+ maxPhotoOneGo: maxPhotoOneGo.intValue,
345
+ tempSessionId: nil,
346
+ imageURI: nil,
347
+ navigationController: nil,
348
+ retake: false,
349
+ metaData: metadataDict
411
350
  )
412
-
413
- let environment = APIEnvironment(rawValue: env as String) ?? .production
414
- InfivizShotsSDK.shared.initializeEnvironent(environment)
415
- activity = InfivizShotsActivity(model: model)
416
- activity?.initialize { result in
417
- switch result {
418
- case .success(let success):
419
- resolve(success)
420
- case .failure(let error):
421
- reject("LOGIN_FAILED", error.localizedDescription, nil)
422
- }
423
- }
424
- }
425
-
426
- @objc
427
- func fetchSessionID(_ taskCategory: NSString,
428
- storeID: NSString,
429
- taskPhotoType: NSString,
430
- resolver resolve: @escaping RCTPromiseResolveBlock,
431
- rejecter reject: @escaping RCTPromiseRejectBlock) {
432
-
433
- InfivizShotsSDK.shared.fetchSessionID(
434
- taskCategory: taskCategory as String,
435
- storeID: storeID as String,
436
- taskPhotoType: taskPhotoType as String
437
- ) { sessionID, error in
438
- if let id = sessionID {
439
- resolve(id)
440
- } else {
441
- reject("SESSION_NOT_FOUND", "Session not found", nil)
442
- }
351
+
352
+ // 2️⃣ Instantiate the SDK activity
353
+ let activity = InfilectSDKCameraActivityForResult(cameraContext: context)
354
+
355
+ // 3️⃣ Call its existing `start(completion:)` which will handle validation,
356
+ activity.start { result in
357
+ switch result {
358
+ case .success(let sessionID):
359
+ resolve(sessionID)
360
+ case .failure(let apiError):
361
+ reject("CAMERA_ERROR", apiError.localizedDescription, nil)
362
+ }
443
363
  }
364
+ }
444
365
  }
445
-
446
- // MARK: - View IR Results via bridge
447
- @objc(viewIRResults:resolver:rejecter:)
448
- func viewIRResults(_ sessionID: NSString,
366
+
367
+ @objc
368
+ func initialize(_ appID: NSString,
369
+ authSecret: NSString,
370
+ accountKey: NSString,
371
+ userID: NSString,
372
+ clientID: NSString,
373
+ apiToken: NSString,
374
+ env: NSString,
449
375
  resolver resolve: @escaping RCTPromiseResolveBlock,
450
- rejecter reject: @escaping RCTPromiseRejectBlock) {
451
- DispatchQueue.main.async {
452
- guard let navigationController = UIApplication.shared.connectedScenes
453
- .compactMap({ $0 as? UIWindowScene })
454
- .flatMap({ $0.windows })
455
- .first(where: { $0.isKeyWindow })?
456
- .rootViewController?.navigationController else {
457
- reject("NAV_ERROR", "No navigation controller available", nil)
458
- return
459
- }
460
- let realTimeView = InfivizRealTimeView(sessionID: sessionID as String,
461
- navigationController: navigationController)
462
- realTimeView.viewIRResults(sessionID: sessionID as String) { result in
463
- switch result {
464
- case .success(let value): resolve(value)
465
- case .failure(let error): reject("VIEW_IR_FAILED", error.localizedDescription, nil)
466
- }
467
- }
468
- }
469
- }
470
-
471
- // MARK: - Start Actions Workflow via bridge
472
- @objc(startActionsWorkFlow:sessionId:latitude:longitude:dateTimeStamp:resolver:rejecter:)
473
- func startActionsWorkFlow(_ storeId: NSString,
474
- sessionId: NSString,
475
- latitude: NSString,
476
- longitude: NSString,
477
- dateTimeStamp: NSString,
478
- resolver resolve: @escaping RCTPromiseResolveBlock,
479
- rejecter reject: @escaping RCTPromiseRejectBlock) {
480
- DispatchQueue.main.async {
481
- guard let navigationController = UIApplication.shared.connectedScenes
482
- .compactMap({ $0 as? UIWindowScene })
483
- .flatMap({ $0.windows })
484
- .first(where: { $0.isKeyWindow })?
485
- .rootViewController?.navigationController else {
486
- reject("NAV_ERROR", "No navigation controller available", nil)
487
- return
488
- }
489
- let realTimeView = InfivizRealTimeView(sessionID: sessionId as String,
490
- navigationController: navigationController)
491
- realTimeView.startActionsWorkFlow(storeId: storeId as String,
492
- sessionId: sessionId as String,
493
- latitude: latitude as String,
494
- longitude: longitude as String,
495
- dateTimeStamp: dateTimeStamp as String) { result in
496
- switch result {
497
- case .success(let value): resolve(value)
498
- case .failure(let error): reject("ACTIONS_WORKFLOW_FAILED", error.localizedDescription, nil)
499
- }
500
- }
501
- }
502
- }
503
-
504
- @objc(resumeCamera:metaData:resolver:rejecter:)
376
+ rejecter reject: @escaping RCTPromiseRejectBlock) {
377
+
378
+ let model = InfivizUserLoginContext(
379
+ appID: appID as String,
380
+ authSecret: authSecret as String,
381
+ accountKey: accountKey as String,
382
+ userID: userID as String,
383
+ clientID: clientID as String,
384
+ apiToken: apiToken as String
385
+ )
386
+
387
+ let environment = APIEnvironment(rawValue: env as String) ?? .production
388
+ InfivizShotsSDK.shared.initializeEnvironent(environment)
389
+ activity = InfivizShotsActivity(model: model)
390
+ activity?.initialize { result in
391
+ switch result {
392
+ case .success(let success):
393
+ resolve(success)
394
+ case .failure(let error):
395
+ reject("LOGIN_FAILED", error.localizedDescription, nil)
396
+ }
397
+ }
398
+ }
399
+
400
+ @objc
401
+ func fetchSessionID(_ taskCategory: NSString,
402
+ storeID: NSString,
403
+ taskPhotoType: NSString,
404
+ resolver resolve: @escaping RCTPromiseResolveBlock,
405
+ rejecter reject: @escaping RCTPromiseRejectBlock) {
406
+
407
+ InfivizShotsSDK.shared.fetchSessionID(
408
+ taskCategory: taskCategory as String,
409
+ storeID: storeID as String,
410
+ taskPhotoType: taskPhotoType as String
411
+ ) { sessionID, error in
412
+ if let id = sessionID {
413
+ resolve(id)
414
+ } else {
415
+ reject("SESSION_NOT_FOUND", "Session not found", nil)
416
+ }
417
+ }
418
+ }
419
+
420
+ // MARK: - View IR Results via bridge
421
+ @objc(viewIRResults:resolver:rejecter:)
422
+ func viewIRResults(_ sessionID: NSString,
423
+ resolver resolve: @escaping RCTPromiseResolveBlock,
424
+ rejecter reject: @escaping RCTPromiseRejectBlock) {
425
+ DispatchQueue.main.async {
426
+ guard let navigationController = UIApplication.shared.connectedScenes
427
+ .compactMap({ $0 as? UIWindowScene })
428
+ .flatMap({ $0.windows })
429
+ .first(where: { $0.isKeyWindow })?
430
+ .rootViewController?.navigationController else {
431
+ reject("NAV_ERROR", "No navigation controller available", nil)
432
+ return
433
+ }
434
+ let realTimeView = InfivizRealTimeView(sessionID: sessionID as String,
435
+ navigationController: navigationController)
436
+ realTimeView.viewIRResults(sessionID: sessionID as String) { result in
437
+ switch result {
438
+ case .success(let value): resolve(value)
439
+ case .failure(let error): reject("VIEW_IR_FAILED", error.localizedDescription, nil)
440
+ }
441
+ }
442
+ }
443
+ }
444
+
445
+ // MARK: - Start Actions Workflow via bridge
446
+ @objc(startActionsWorkFlow:sessionId:latitude:longitude:dateTimeStamp:resolver:rejecter:)
447
+ func startActionsWorkFlow(_ storeId: NSString,
448
+ sessionId: NSString,
449
+ latitude: NSString,
450
+ longitude: NSString,
451
+ dateTimeStamp: NSString,
452
+ resolver resolve: @escaping RCTPromiseResolveBlock,
453
+ rejecter reject: @escaping RCTPromiseRejectBlock) {
454
+ DispatchQueue.main.async {
455
+ guard let navigationController = UIApplication.shared.connectedScenes
456
+ .compactMap({ $0 as? UIWindowScene })
457
+ .flatMap({ $0.windows })
458
+ .first(where: { $0.isKeyWindow })?
459
+ .rootViewController?.navigationController else {
460
+ reject("NAV_ERROR", "No navigation controller available", nil)
461
+ return
462
+ }
463
+ let realTimeView = InfivizRealTimeView(sessionID: sessionId as String,
464
+ navigationController: navigationController)
465
+ realTimeView.startActionsWorkFlow(storeId: storeId as String,
466
+ sessionId: sessionId as String,
467
+ latitude: latitude as String,
468
+ longitude: longitude as String,
469
+ dateTimeStamp: dateTimeStamp as String) { result in
470
+ switch result {
471
+ case .success(let value): resolve(value)
472
+ case .failure(let error): reject("ACTIONS_WORKFLOW_FAILED", error.localizedDescription, nil)
473
+ }
474
+ }
475
+ }
476
+ }
477
+
478
+ @objc(resumeCamera:metaData:resolver:rejecter:)
505
479
  func resumeCamera(
506
- _ temporarySessionID: NSString,
507
- metaData: NSDictionary?,
508
- resolver resolve: @escaping RCTPromiseResolveBlock,
509
- rejecter reject: @escaping RCTPromiseRejectBlock
480
+ _ temporarySessionID: NSString,
481
+ metaData: NSDictionary?,
482
+ resolver resolve: @escaping RCTPromiseResolveBlock,
483
+ rejecter reject: @escaping RCTPromiseRejectBlock
510
484
  ) {
511
- // Build whatever CameraContext your SDK needs. In your original UI code,
512
- // you were reading from text fields (e.g. shelfTextField.text, traderTextField.text, etc.).
513
- // In a module method you typically won't have those outlets available, so you'll
514
- // need to pass any required "taskName", "storeTitle" etc. from JS into this call
515
- // or hard‐code defaults here. For now, I'll show a minimal example:
516
-
517
- let context = CameraContext(
518
- taskName: "", // ← pass in from JS if you really need it
519
- storeTitle: "",
520
- storeId: "",
521
- photoType: "",
522
- category: "",
523
- maxPhoto: 0,
524
- maxPhotoOneGo: 0,
525
- navigationController: nil // ← no UIKit nav controller in RN module
526
- )
527
-
528
- // Instantiate your SDK's camera controller just like before:
529
- let controller = InfilectSDKCameraActivityForResult(cameraContext: context)
530
-
531
- // Convert NSDictionary to [String: Any]
532
- let metadataDict: [String: Any]? = metaData as? [String: Any]
533
-
534
- // Call the updated `resumeCamera(sessionID:metaData:completion:)` API with metadata
535
- controller.resumeCamera(sessionID: temporarySessionID as String, metaData: metadataDict) { result in
536
- switch result {
537
- case .success(let successString):
538
- // fulfill the JS promise with the returned string
539
- resolve(successString)
540
-
541
- case .failure(let sdkError):
542
- // reject the JS promise
543
- let nsError = sdkError as NSError
544
- reject(
545
- "ResumeCameraError",
546
- "Failed to resume camera: \(nsError.localizedDescription)",
547
- nsError
548
- )
549
- }
550
- }
551
- }
552
-
553
- @objc
554
- func deletePhoto(
555
- _ imageURI: NSString,
556
- temporarySessionId: NSString,
557
- resolver resolve: @escaping RCTPromiseResolveBlock,
558
- rejecter reject: @escaping RCTPromiseRejectBlock
559
- ) {
560
- let context = CameraContext(
561
- taskName: "",
562
- storeTitle: "",
563
- storeId: "",
564
- photoType: "",
565
-
566
- category: "",
567
- maxPhoto: 0,
568
- maxPhotoOneGo: 0,
569
- navigationController: nil
570
- )
571
- let controller = InfilectSDKCameraActivityForResult(cameraContext: context)
572
- controller.deleteImage(imageID: imageURI as String, sessionID: temporarySessionId as String) { result in
573
- switch result {
574
- case .success(let successMessage):
575
- resolve(successMessage)
576
- case .failure(let error):
577
- reject("DELETE_IMAGE_ERROR", "Failed to delete image: \(error.localizedDescription)", error)
578
- }
485
+ // Build whatever CameraContext your SDK needs. In your original UI code,
486
+ // you were reading from text fields (e.g. shelfTextField.text, traderTextField.text, etc.).
487
+ // In a module method you typically won't have those outlets available, so you'll
488
+ // need to pass any required "taskName", "storeTitle" etc. from JS into this call
489
+ // or hard‐code defaults here. For now, I'll show a minimal example:
490
+
491
+ let context = CameraContext(
492
+ taskName: "", // ← pass in from JS if you really need it
493
+ storeTitle: "",
494
+ storeId: "",
495
+ photoType: "",
496
+ category: "",
497
+ maxPhoto: 0,
498
+ maxPhotoOneGo: 0,
499
+ navigationController: nil // ← no UIKit nav controller in RN module
500
+ )
501
+
502
+ // Instantiate your SDK's camera controller just like before:
503
+ let controller = InfilectSDKCameraActivityForResult(cameraContext: context)
504
+
505
+ // Convert NSDictionary to [String: Any]
506
+ let metadataDict: [String: Any]? = metaData as? [String: Any]
507
+
508
+ // Call the updated `resumeCamera(sessionID:metaData:completion:)` API with metadata
509
+ controller.resumeCamera(sessionID: temporarySessionID as String, metaData: metadataDict) { result in
510
+ switch result {
511
+ case .success(let successString):
512
+ // fulfill the JS promise with the returned string
513
+ resolve(successString)
514
+
515
+ case .failure(let sdkError):
516
+ // reject the JS promise
517
+ let nsError = sdkError as NSError
518
+ reject(
519
+ "ResumeCameraError",
520
+ "Failed to resume camera: \(nsError.localizedDescription)",
521
+ nsError
522
+ )
579
523
  }
524
+ }
580
525
  }
581
-
526
+
527
+ @objc
528
+ func deletePhoto(
529
+ _ imageURI: NSString,
530
+ temporarySessionId: NSString,
531
+ resolver resolve: @escaping RCTPromiseResolveBlock,
532
+ rejecter reject: @escaping RCTPromiseRejectBlock
533
+ ) {
534
+ let context = CameraContext(
535
+ taskName: "",
536
+ storeTitle: "",
537
+ storeId: "",
538
+ photoType: "",
539
+
540
+ category: "",
541
+ maxPhoto: 0,
542
+ maxPhotoOneGo: 0,
543
+ navigationController: nil
544
+ )
545
+ let controller = InfilectSDKCameraActivityForResult(cameraContext: context)
546
+ controller.deleteImage(imageID: imageURI as String, sessionID: temporarySessionId as String) { result in
547
+ switch result {
548
+ case .success(let successMessage):
549
+ resolve(successMessage)
550
+ case .failure(let error):
551
+ reject("DELETE_IMAGE_ERROR", "Failed to delete image: \(error.localizedDescription)", error)
552
+ }
553
+ }
554
+ }
555
+
582
556
  @objc(retakeImage:imageURL:metaData:resolver:rejecter:)
583
557
  func retakeImage(
584
558
  _ temporarySessionId: NSString,
@@ -619,70 +593,70 @@ class InfivizShotsReactSdk: RCTEventEmitter {
619
593
  }
620
594
  }
621
595
  }
622
-
623
- // MARK: – React Native Promise Exposures for OutputAPI
624
- /// Expose `getIRResult(sessionID:completion:)` to JavaScript as:
625
- /// InfiBridge.getIRResult("session-123").then(...).catch(...)
626
- @objc
627
- func getIrResult(
628
- _ sessionId: NSString,
629
- resolver resolve: @escaping RCTPromiseResolveBlock,
630
- rejecter reject: @escaping RCTPromiseRejectBlock
631
- ) {
632
- print("Inside GetIrResult sessionId -> \(sessionId)")
633
- // Call the Swift helper (which calls outputAPI.getIRResult)
634
- InfivizShotsSDK.shared.getIrResult(sessionID: sessionId as String) { (dataAny, error) in
635
- if let err = error {
636
- // If the SDK returned an error, reject the JS promise
637
- print("err", err)
638
- reject(
639
- "IR_RESULT_ERROR", // error code (custom identifier)
640
- err as? String, // error message
641
- nil // optional NSError (can be nil)
642
- )
643
- } else if let output = dataAny {
644
- // If the SDK returned data (Any), pass it back to JS.
645
- resolve(output)
646
- } else {
647
- // Neither data nor error? Just resolve with `nil`.
648
- resolve(nil)
649
- }
650
- }
651
- }
652
-
653
- /// Expose `getActionsResult(sessionID:completion:)` to JavaScript as:
654
- /// InfiBridge.getActionsResult("session-123").then(...).catch(...)
655
- @objc
656
- func getActionsResult(
657
- _ sessionId: NSString,
658
- resolver resolve: @escaping RCTPromiseResolveBlock,
659
- rejecter reject: @escaping RCTPromiseRejectBlock
660
- ) {
661
- // Call the Swift helper (which calls outputAPI.getActionsResult)
662
- InfivizShotsSDK.shared.getActionsResult(sessionID: sessionId as String) { (dataAny, error) in
663
- if let err = error {
664
- reject("ACTIONS_FAILED", err as? String, nil)
665
- } else if let output = dataAny {
666
- resolve(output)
667
- } else {
668
- resolve(nil)
669
- }
596
+
597
+ // MARK: – React Native Promise Exposures for OutputAPI
598
+ /// Expose `getIRResult(sessionID:completion:)` to JavaScript as:
599
+ /// InfiBridge.getIRResult("session-123").then(...).catch(...)
600
+ @objc
601
+ func getIrResult(
602
+ _ sessionId: NSString,
603
+ resolver resolve: @escaping RCTPromiseResolveBlock,
604
+ rejecter reject: @escaping RCTPromiseRejectBlock
605
+ ) {
606
+ print("Inside GetIrResult sessionId -> \(sessionId)")
607
+ // Call the Swift helper (which calls outputAPI.getIRResult)
608
+ InfivizShotsSDK.shared.getIrResult(sessionID: sessionId as String) { (dataAny, error) in
609
+ if let err = error {
610
+ // If the SDK returned an error, reject the JS promise
611
+ print("err", err)
612
+ reject(
613
+ "IR_RESULT_ERROR", // error code (custom identifier)
614
+ err as? String, // error message
615
+ nil // optional NSError (can be nil)
616
+ )
617
+ } else if let output = dataAny {
618
+ // If the SDK returned data (Any), pass it back to JS.
619
+ resolve(output)
620
+ } else {
621
+ // Neither data nor error? Just resolve with `nil`.
622
+ resolve(nil)
623
+ }
624
+ }
625
+ }
626
+
627
+ /// Expose `getActionsResult(sessionID:completion:)` to JavaScript as:
628
+ /// InfiBridge.getActionsResult("session-123").then(...).catch(...)
629
+ @objc
630
+ func getActionsResult(
631
+ _ sessionId: NSString,
632
+ resolver resolve: @escaping RCTPromiseResolveBlock,
633
+ rejecter reject: @escaping RCTPromiseRejectBlock
634
+ ) {
635
+ // Call the Swift helper (which calls outputAPI.getActionsResult)
636
+ InfivizShotsSDK.shared.getActionsResult(sessionID: sessionId as String) { (dataAny, error) in
637
+ if let err = error {
638
+ reject("ACTIONS_FAILED", err as? String, nil)
639
+ } else if let output = dataAny {
640
+ resolve(output)
641
+ } else {
642
+ resolve(nil)
643
+ }
644
+ }
645
+ }
646
+
647
+ @objc
648
+ private func handleActionsGeneratedEvent(_ notification: Notification) {
649
+ guard hasListeners else { return }
650
+
651
+ let payload = notification.userInfo ?? [:]
652
+ sendEvent(withName: "ActionsGeneratedEvent", body: payload)
670
653
  }
671
- }
672
-
673
- @objc
674
- private func handleActionsGeneratedEvent(_ notification: Notification) {
675
- guard hasListeners else { return }
676
654
 
677
- let payload = notification.userInfo ?? [:]
678
- sendEvent(withName: "ActionsGeneratedEvent", body: payload)
679
- }
680
-
681
- @objc
682
- private func handleSessionRealTimeResultEvent(_ notification: Notification) {
683
- guard hasListeners else { return }
684
-
685
- let payload = notification.userInfo ?? [:]
686
- sendEvent(withName: "SessionRealTimeResultEvent", body: payload)
687
- }
655
+ @objc
656
+ private func handleSessionRealTimeResultEvent(_ notification: Notification) {
657
+ guard hasListeners else { return }
658
+
659
+ let payload = notification.userInfo ?? [:]
660
+ sendEvent(withName: "SessionRealTimeResultEvent", body: payload)
661
+ }
688
662
  }