@infilectorg/infiviz-shots-react-sdk 1.0.46 → 1.0.47
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/android/build.gradle +1 -1
- package/ios/InfivizShotSDK.xcframework/Info.plist +5 -5
- package/ios/InfivizShotSDK.xcframework/ios-arm64/InfivizShotSDK.framework/Assets.car +0 -0
- package/ios/InfivizShotSDK.xcframework/ios-arm64/InfivizShotSDK.framework/InfivizShotSDK +0 -0
- package/ios/InfivizShotSDK.xcframework/ios-arm64/InfivizShotSDK.framework/Modules/InfivizShotSDK.swiftmodule/arm64-apple-ios.abi.json +60 -60
- package/ios/InfivizShotSDK.xcframework/ios-arm64/InfivizShotSDK.framework/Modules/InfivizShotSDK.swiftmodule/arm64-apple-ios.swiftmodule +0 -0
- package/ios/InfivizShotSDK.xcframework/ios-arm64/InfivizShotSDK.framework/shotsSDK.storyboardc/xUL-ol-gRQ-view-6A8-mO-Rhi.nib +0 -0
- package/ios/InfivizShotSDK.xcframework/ios-arm64_x86_64-simulator/InfivizShotSDK.framework/InfivizShotSDK +0 -0
- package/ios/InfivizShotSDK.xcframework/ios-arm64_x86_64-simulator/InfivizShotSDK.framework/Modules/InfivizShotSDK.swiftmodule/arm64-apple-ios-simulator.abi.json +60 -60
- package/ios/InfivizShotSDK.xcframework/ios-arm64_x86_64-simulator/InfivizShotSDK.framework/Modules/InfivizShotSDK.swiftmodule/arm64-apple-ios-simulator.swiftmodule +0 -0
- package/ios/InfivizShotSDK.xcframework/ios-arm64_x86_64-simulator/InfivizShotSDK.framework/Modules/InfivizShotSDK.swiftmodule/x86_64-apple-ios-simulator.abi.json +60 -60
- package/ios/InfivizShotSDK.xcframework/ios-arm64_x86_64-simulator/InfivizShotSDK.framework/Modules/InfivizShotSDK.swiftmodule/x86_64-apple-ios-simulator.swiftmodule +0 -0
- package/ios/InfivizShotSDK.xcframework/ios-arm64_x86_64-simulator/InfivizShotSDK.framework/shotsSDK.storyboardc/xUL-ol-gRQ-view-6A8-mO-Rhi.nib +0 -0
- package/ios/InfivizShotsReactSdk.swift +570 -593
- package/lib/module/NativeInfivizShotsReactSdk.js +2 -0
- package/lib/module/NativeInfivizShotsReactSdk.js.map +1 -1
- package/lib/module/index.js +4 -2
- package/lib/module/index.js.map +1 -1
- package/lib/module/package.json +1 -0
- package/lib/module/types/Environment.js +2 -0
- package/lib/module/types/Environment.js.map +1 -1
- package/lib/module/types/ImageMetaData.js +2 -0
- package/lib/module/types/ImageMetaData.js.map +1 -1
- package/lib/module/types/InfiSession.js +2 -0
- package/lib/module/types/InfiSession.js.map +1 -1
- package/lib/module/types/LabelScore.js +1 -1
- package/lib/module/types/LabelScore.js.map +1 -1
- package/lib/module/types/SessionStatus.js +1 -1
- package/lib/module/types/SessionStatus.js.map +1 -1
- package/lib/module/types/SessionSyncStateEnum.js +2 -0
- package/lib/module/types/SessionSyncStateEnum.js.map +1 -1
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativeInfivizShotsReactSdk.d.ts +23 -0
- package/lib/typescript/src/NativeInfivizShotsReactSdk.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +24 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/types/Environment.d.ts +5 -0
- package/lib/typescript/src/types/Environment.d.ts.map +1 -0
- package/lib/typescript/src/types/ImageMetaData.d.ts +13 -0
- package/lib/typescript/src/types/ImageMetaData.d.ts.map +1 -0
- package/lib/typescript/src/types/InfiSession.d.ts +18 -0
- package/lib/typescript/src/types/InfiSession.d.ts.map +1 -0
- package/lib/typescript/src/types/LabelScore.d.ts +5 -0
- package/lib/typescript/src/types/LabelScore.d.ts.map +1 -0
- package/lib/typescript/src/types/SessionStatus.d.ts +5 -0
- package/lib/typescript/src/types/SessionStatus.d.ts.map +1 -0
- package/lib/typescript/src/types/SessionSyncStateEnum.d.ts +8 -0
- package/lib/typescript/src/types/SessionSyncStateEnum.d.ts.map +1 -0
- package/package.json +1 -1
- package/react-native-infiviz-shots.podspec +1 -1
|
@@ -12,336 +12,313 @@ import React
|
|
|
12
12
|
|
|
13
13
|
@objc(InfivizShotsReactSdk)
|
|
14
14
|
class InfivizShotsReactSdk: RCTEventEmitter {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
-
|
|
116
|
+
ids = arr
|
|
117
117
|
} else if let arr = temporarySessionIDs as? [NSString] {
|
|
118
|
-
|
|
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
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
|
|
148
|
-
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// MARK: - Get Session Result
|
|
148
|
+
|
|
149
149
|
@objc
|
|
150
150
|
func getSessionStatus(
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
151
|
+
_ temporarySessionID: NSString,
|
|
152
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
153
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
154
154
|
) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
-
// 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
|
-
// MARK: - Convert Any Value 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 if let dict = value as? [AnyHashable: Any] {
|
|
211
|
-
var result: [String: Any] = [:]
|
|
212
|
-
for (k, v) in dict {
|
|
213
|
-
result[String(describing: k)] = unwrapOptional(v)
|
|
214
|
-
}
|
|
215
|
-
return result
|
|
216
|
-
} else {
|
|
217
|
-
// Try to convert to dictionary using Mirror reflection
|
|
218
|
-
let mirror = Mirror(reflecting: value)
|
|
219
|
-
var result: [String: Any] = [:]
|
|
220
|
-
for child in mirror.children {
|
|
221
|
-
if let label = child.label {
|
|
222
|
-
result[label] = unwrapOptional(child.value)
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
return result
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// MARK: - Recursively Clean Dictionary
|
|
230
|
-
private func cleanDictionary(_ dict: [String: Any]) -> [String: Any] {
|
|
231
|
-
var cleaned: [String: Any] = [:]
|
|
232
|
-
for (key, value) in dict {
|
|
233
|
-
cleaned[key] = unwrapOptional(value)
|
|
234
|
-
}
|
|
235
|
-
return cleaned
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// MARK: - Unwrap Optionals and Clean Nested Structures
|
|
239
|
-
private func unwrapOptional(_ value: Any) -> Any {
|
|
240
|
-
let mirror = Mirror(reflecting: value)
|
|
241
|
-
|
|
242
|
-
// 1. Handle Optional
|
|
243
|
-
let typeName = String(describing: type(of: value))
|
|
244
|
-
if typeName.hasPrefix("Optional<") {
|
|
245
|
-
if let unwrapped = mirror.children.first?.value {
|
|
246
|
-
return unwrapOptional(unwrapped)
|
|
247
|
-
} else {
|
|
248
|
-
return NSNull()
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// 2. Strings cleanup
|
|
253
|
-
if let str = value as? String {
|
|
254
|
-
return str.replacingOccurrences(of: "Optional\\(|\\)",
|
|
255
|
-
with: "",
|
|
256
|
-
options: .regularExpression)
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// 3. Arrays
|
|
260
|
-
if let array = value as? [Any] {
|
|
261
|
-
return array.map { unwrapOptional($0) }
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// 4. Dictionaries
|
|
265
|
-
if let dict = value as? [String: Any] {
|
|
266
|
-
// 👇 Detect special case: metadata dictionaries
|
|
267
|
-
if dict.keys.count == 1, let firstKey = dict.keys.first {
|
|
268
|
-
if ["string", "bool", "int", "double", "float"].contains(firstKey.lowercased()) {
|
|
269
|
-
return unwrapOptional(dict[firstKey]!)
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
return cleanDictionary(dict)
|
|
273
|
-
} else if let dict = value as? [AnyHashable: Any] {
|
|
274
|
-
var result: [String: Any] = [:]
|
|
275
|
-
for (k, v) in dict {
|
|
276
|
-
result[String(describing: k)] = unwrapOptional(v)
|
|
277
|
-
}
|
|
278
|
-
return result
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// 5. Dates
|
|
282
|
-
if let date = value as? Date {
|
|
283
|
-
let formatter = DateFormatter()
|
|
284
|
-
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
|
|
285
|
-
return formatter.string(from: date)
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// 6. Custom objects
|
|
289
|
-
let objectMirror = Mirror(reflecting: value)
|
|
290
|
-
if !objectMirror.children.isEmpty {
|
|
291
|
-
var result: [String: Any] = [:]
|
|
292
|
-
for child in objectMirror.children {
|
|
293
|
-
if let label = child.label {
|
|
294
|
-
result[label] = unwrapOptional(child.value)
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
return result
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// 7. Primitives
|
|
301
|
-
return value
|
|
302
|
-
}
|
|
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]
|
|
303
160
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
func logout(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
308
|
-
InfivizShotsSDK.shared.callLogoutAPI { result in
|
|
309
|
-
switch result {
|
|
310
|
-
case .success(let success):
|
|
311
|
-
resolve(success)
|
|
312
|
-
case .failure(let error):
|
|
313
|
-
reject("LOGOUT_FAILED", "Logout error: \(error)", nil)
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// MARK: - Reprocessing Enable Time
|
|
319
|
-
@objc
|
|
320
|
-
func getReprocessingButtonEnableTime(_ sessionID: NSString, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
321
|
-
InfivizShotsSDK.shared.getReprocessingButtonEnableTime(sessionID: sessionID as String) { result in
|
|
322
|
-
switch result {
|
|
323
|
-
case .success(let time):
|
|
324
|
-
resolve(time)
|
|
325
|
-
case .failure(let error):
|
|
326
|
-
reject("REPROCESS_TIME_ERROR", "Error fetching reprocessing time: \(error)", nil)
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// MARK: - Start Reprocessing Workflow
|
|
332
|
-
@objc
|
|
333
|
-
func startReprocessingWorkflow(_ sessionID: NSString, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
334
|
-
InfivizShotsSDK.shared.startReprocessingWorkflow(sessionID: sessionID as String) { result in
|
|
335
|
-
switch result {
|
|
336
|
-
case .success(let time):
|
|
337
|
-
resolve(time)
|
|
338
|
-
case .failure(let error):
|
|
339
|
-
reject("REPROCESS_WORKFLOW_ERROR", "Reprocessing workflow error: \(error)", nil)
|
|
161
|
+
if let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []) {
|
|
162
|
+
let jsonString = String(data: jsonData, encoding: .utf8)
|
|
163
|
+
resolve(jsonString)
|
|
340
164
|
}
|
|
165
|
+
|
|
166
|
+
case .failure(let error):
|
|
167
|
+
reject(
|
|
168
|
+
"RESULT_FAILED",
|
|
169
|
+
"Failed to get result for \(temporarySessionID): \(error.localizedDescription)",
|
|
170
|
+
nil
|
|
171
|
+
)
|
|
341
172
|
}
|
|
173
|
+
}
|
|
342
174
|
}
|
|
343
|
-
|
|
344
|
-
|
|
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
|
+
// 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
|
+
}
|
|
281
|
+
|
|
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
|
+
}
|
|
294
|
+
|
|
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
|
+
}
|
|
307
|
+
|
|
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
|
+
}
|
|
320
|
+
|
|
321
|
+
// MARK: - Start Camera
|
|
345
322
|
@objc(startCamera:storeTitle:storeId:photoType:category:maxPhoto:maxPhotoOneGo:metaData:resolver:rejecter:)
|
|
346
323
|
func startCamera(_ taskName: NSString,
|
|
347
324
|
storeTitle: NSString,
|
|
@@ -353,229 +330,229 @@ class InfivizShotsReactSdk: RCTEventEmitter {
|
|
|
353
330
|
metaData: NSDictionary,
|
|
354
331
|
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
355
332
|
rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
)
|
|
374
|
-
|
|
375
|
-
// 2️⃣ Instantiate the SDK activity
|
|
376
|
-
let activity = InfilectSDKCameraActivityForResult(cameraContext: context)
|
|
377
|
-
|
|
378
|
-
// 3️⃣ Call its existing `start(completion:)` which will handle validation,
|
|
379
|
-
activity.start { result in
|
|
380
|
-
switch result {
|
|
381
|
-
case .success(let sessionID):
|
|
382
|
-
resolve(sessionID)
|
|
383
|
-
case .failure(let apiError):
|
|
384
|
-
reject("CAMERA_ERROR", apiError.localizedDescription, nil)
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
@objc
|
|
391
|
-
func initialize(_ appID: NSString,
|
|
392
|
-
authSecret: NSString,
|
|
393
|
-
accountKey: NSString,
|
|
394
|
-
userID: NSString,
|
|
395
|
-
clientID: NSString,
|
|
396
|
-
apiToken: NSString,
|
|
397
|
-
env: NSString,
|
|
398
|
-
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
399
|
-
rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
400
|
-
|
|
401
|
-
let model = InfivizUserLoginContext(
|
|
402
|
-
appID: appID as String,
|
|
403
|
-
authSecret: authSecret as String,
|
|
404
|
-
accountKey: accountKey as String,
|
|
405
|
-
userID: userID as String,
|
|
406
|
-
clientID: clientID as String,
|
|
407
|
-
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
|
|
408
350
|
)
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
@objc
|
|
424
|
-
func fetchSessionID(_ taskCategory: NSString,
|
|
425
|
-
storeID: NSString,
|
|
426
|
-
taskPhotoType: NSString,
|
|
427
|
-
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
428
|
-
rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
429
|
-
|
|
430
|
-
InfivizShotsSDK.shared.fetchSessionID(
|
|
431
|
-
taskCategory: taskCategory as String,
|
|
432
|
-
storeID: storeID as String,
|
|
433
|
-
taskPhotoType: taskPhotoType as String
|
|
434
|
-
) { sessionID, error in
|
|
435
|
-
if let id = sessionID {
|
|
436
|
-
resolve(id)
|
|
437
|
-
} else {
|
|
438
|
-
reject("SESSION_NOT_FOUND", "Session not found", nil)
|
|
439
|
-
}
|
|
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
|
+
}
|
|
440
363
|
}
|
|
364
|
+
}
|
|
441
365
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
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,
|
|
446
375
|
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
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:)
|
|
502
479
|
func resumeCamera(
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
) {
|
|
508
|
-
// Build whatever CameraContext your SDK needs. In your original UI code,
|
|
509
|
-
// you were reading from text fields (e.g. shelfTextField.text, traderTextField.text, etc.).
|
|
510
|
-
// In a module method you typically won't have those outlets available, so you'll
|
|
511
|
-
// need to pass any required "taskName", "storeTitle" etc. from JS into this call
|
|
512
|
-
// or hard‐code defaults here. For now, I'll show a minimal example:
|
|
513
|
-
|
|
514
|
-
let context = CameraContext(
|
|
515
|
-
taskName: "", // ← pass in from JS if you really need it
|
|
516
|
-
storeTitle: "",
|
|
517
|
-
storeId: "",
|
|
518
|
-
photoType: "",
|
|
519
|
-
category: "",
|
|
520
|
-
maxPhoto: 0,
|
|
521
|
-
maxPhotoOneGo: 0,
|
|
522
|
-
navigationController: nil // ← no UIKit nav controller in RN module
|
|
523
|
-
)
|
|
524
|
-
|
|
525
|
-
// Instantiate your SDK's camera controller just like before:
|
|
526
|
-
let controller = InfilectSDKCameraActivityForResult(cameraContext: context)
|
|
527
|
-
|
|
528
|
-
// Convert NSDictionary to [String: Any]
|
|
529
|
-
let metadataDict: [String: Any]? = metaData as? [String: Any]
|
|
530
|
-
|
|
531
|
-
// Call the updated `resumeCamera(sessionID:metaData:completion:)` API with metadata
|
|
532
|
-
controller.resumeCamera(sessionID: temporarySessionID as String, metaData: metadataDict) { result in
|
|
533
|
-
switch result {
|
|
534
|
-
case .success(let successString):
|
|
535
|
-
// fulfill the JS promise with the returned string
|
|
536
|
-
resolve(successString)
|
|
537
|
-
|
|
538
|
-
case .failure(let sdkError):
|
|
539
|
-
// reject the JS promise
|
|
540
|
-
let nsError = sdkError as NSError
|
|
541
|
-
reject(
|
|
542
|
-
"ResumeCameraError",
|
|
543
|
-
"Failed to resume camera: \(nsError.localizedDescription)",
|
|
544
|
-
nsError
|
|
545
|
-
)
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
@objc
|
|
551
|
-
func deletePhoto(
|
|
552
|
-
_ imageURI: NSString,
|
|
553
|
-
temporarySessionId: NSString,
|
|
554
|
-
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
555
|
-
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
480
|
+
_ temporarySessionID: NSString,
|
|
481
|
+
metaData: NSDictionary?,
|
|
482
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
483
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
556
484
|
) {
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
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
|
+
)
|
|
576
523
|
}
|
|
524
|
+
}
|
|
577
525
|
}
|
|
578
|
-
|
|
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
|
+
|
|
579
556
|
@objc(retakeImage:imageURL:metaData:resolver:rejecter:)
|
|
580
557
|
func retakeImage(
|
|
581
558
|
_ temporarySessionId: NSString,
|
|
@@ -616,70 +593,70 @@ class InfivizShotsReactSdk: RCTEventEmitter {
|
|
|
616
593
|
}
|
|
617
594
|
}
|
|
618
595
|
}
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
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)
|
|
667
653
|
}
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
@objc
|
|
671
|
-
private func handleActionsGeneratedEvent(_ notification: Notification) {
|
|
672
|
-
guard hasListeners else { return }
|
|
673
654
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
let payload = notification.userInfo ?? [:]
|
|
683
|
-
sendEvent(withName: "SessionRealTimeResultEvent", body: payload)
|
|
684
|
-
}
|
|
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
|
+
}
|
|
685
662
|
}
|