react-native-pointr 9.9.0 → 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/API_REFERENCE.md +284 -315
  2. package/CHANGELOG.md +36 -0
  3. package/EXTENDING.md +11 -16
  4. package/README.md +14 -14
  5. package/WAYFINDING_EVENTS.md +5 -3
  6. package/android/build.gradle +1 -1
  7. package/android/src/main/java/com/pointr/PTRCoreExtensions.kt +33 -2
  8. package/android/src/main/java/com/pointr/PTRMapWidgetActionType.kt +17 -0
  9. package/android/src/main/java/com/pointr/PTRMapWidgetManager.kt +162 -406
  10. package/android/src/main/java/com/pointr/{PointrModule.kt → PTRNativeLibrary.kt} +150 -32
  11. package/android/src/main/java/com/pointr/{PointrPackage.kt → PTRPackage.kt} +2 -2
  12. package/ios/PTRMapWidgetContainerView.swift +174 -187
  13. package/ios/PTRMapWidgetManager-Bridging.m +12 -64
  14. package/ios/PTRMapWidgetManager.swift +164 -136
  15. package/ios/PTRNativeLibrary-Bridging.m +38 -2
  16. package/ios/PTRNativeLibrary.swift +206 -26
  17. package/package.json +5 -3
  18. package/react-native-pointr.podspec +1 -1
  19. package/src/NativePointrModule.ts +70 -0
  20. package/src/PTRMapWidgetUtils.ts +67 -144
  21. package/src/actions/index.ts +171 -0
  22. package/src/api/MapWidgetApi.ts +8 -8
  23. package/src/api/PointrSdk.ts +50 -91
  24. package/src/components/index.tsx +27 -26
  25. package/src/constants/index.ts +32 -13
  26. package/src/hooks/index.ts +1 -0
  27. package/src/hooks/usePointrGeofences.ts +37 -0
  28. package/src/hooks/usePointrSdk.ts +12 -5
  29. package/src/index.tsx +37 -70
  30. package/src/managers/PTRPoiManager.ts +2 -2
  31. package/src/types/PTRPoi.ts +5 -2
  32. package/src/types/PTRPosition.ts +15 -5
  33. package/src/types/PTRSite.ts +46 -0
  34. package/src/types/PTRWayfindingEvent.ts +11 -7
  35. package/src/types/config.ts +1 -0
  36. package/src/types/events.ts +1 -0
  37. package/src/types/index.ts +4 -0
  38. package/android/src/main/java/com/pointr/PTRMapWidgetCommandType.kt +0 -20
  39. package/src/PTRCommand.ts +0 -153
  40. package/src/api/index.ts +0 -9
  41. package/src/commands/index.ts +0 -275
@@ -1,22 +1,22 @@
1
1
  import UIKit
2
2
  import PointrKit
3
3
 
4
- @objc class PTRMapWidgetContainerView: UIView, PTRSiteManagerDelegate, PTRDataManagerDelegate, PTRWayfindingManagerDelegate, PTRMapWidgetEventsListener {
4
+ @objc class PTRMapWidgetContainerView: UIView, PTRSiteManagerDelegate, PTRDataManagerDelegate {
5
5
 
6
6
  @objc var onMapWidgetDidEndLoading: RCTBubblingEventBlock?
7
-
8
7
  @objc var onWayfindingEvent: RCTBubblingEventBlock?
9
8
 
10
- // Declarative command prop — JSON string encoding command type and its parameters.
9
+
10
+ // Declarative action prop — JSON string encoding action type and its parameters.
11
11
  // When set alongside an optional sdkConfig prop, the widget auto-starts and focuses
12
- // without the JS caller needing to imperatively dispatch a command afterwards.
12
+ // without the JS caller needing to imperatively dispatch an action afterwards.
13
13
  //
14
- // Expected shape: { "type": "site"|"building"|"level"|"poi"|"path"|"staticPath"|"staticWayfinding",
14
+ // Expected shape: { "type": "focusMap"|"highlightPoi"|"displayRoute"|"startWayfinding"|"markMyCar"|"showMyCar"|"focusCoordinate"|"highlightCategory",
15
15
  // "site": "...", "building"?: "...", "level"?: 0,
16
16
  // "poi"?: "...", "fromPoi"?: "...", "toPoi"?: "...",
17
17
  // "sourcePoi"?: "...", "destinationPoi"?: "..." }
18
- @objc var command: String? {
19
- didSet { pendingCommandString = command }
18
+ @objc var action: String? {
19
+ didSet { pendingActionString = action }
20
20
  }
21
21
 
22
22
  // Optional SDK config prop — JSON with clientId / licenseKey / baseUrl / logLevel.
@@ -31,8 +31,8 @@ import PointrKit
31
31
  didSet { applyMapWidgetConfigIfNeeded() }
32
32
  }
33
33
 
34
- private var pendingCommandString: String?
35
- private var commandDidExecute = false
34
+ private var pendingActionString: String?
35
+ private var actionDidExecute = false
36
36
 
37
37
  private(set) var mapWidget: PTRMapWidgetViewController?
38
38
  var semaphore: DispatchSemaphore?
@@ -61,21 +61,39 @@ import PointrKit
61
61
  }
62
62
 
63
63
  func mapWidgetWillPresentWayfinding(_ mapWidget: PTRMapWidgetViewController) {
64
- switch (mapWidget.layoutState) {
65
- case .staticWayfinding(_, let destination, _):
64
+ // Inspect the v10 class-based layout state to determine wayfinding type and destination.
65
+ let state = mapWidget.layoutState
66
+ if let wayfinding = state as? PTRStaticWayfindingLayoutState {
66
67
  print("PTRMapWidget - wayfinding started. Static path")
67
- ptrWayfindingEvent(withParameters: ["type": 0, "poi": destination.dict])
68
- case .wayfinding(let destination, _):
68
+ ptrWayfindingEvent(withParameters: ["type": 0, "poi": wayfinding.destination.dict])
69
+ } else if let wayfinding = state as? PTRWayfindingLayoutState {
69
70
  print("PTRMapWidget - wayfinding started. Dynamic path")
70
- ptrWayfindingEvent(withParameters: ["type": 0, "poi": destination.dict])
71
- default:
71
+ ptrWayfindingEvent(withParameters: ["type": 0, "poi": wayfinding.destination.dict])
72
+ } else {
72
73
  print("PTRMapWidget - Widget presented without wayfinding")
73
74
  }
74
75
  }
75
76
 
76
77
  private var wayfindingEventsAdapter: WayfindingEventsAdapter?
78
+ private var mapWidgetEventsAdapter: MapWidgetEventsAdapter?
77
79
 
78
- private let kLayerStaticPath = "static-path"
80
+ // MARK: - PTRMapWidgetEventsListener adapter (loading + layout state)
81
+ //
82
+ // PTRMapWidgetViewController.addListener has an early-return branch for
83
+ // PTRMapWidgetEventsListener, so it must be a *separate* object from the
84
+ // container – otherwise the container (conforming to other listener protocols)
85
+ // would never make it into the registeredListeners set.
86
+ private class MapWidgetEventsAdapter: NSObject, PTRMapWidgetEventsListener {
87
+ weak var container: PTRMapWidgetContainerView?
88
+
89
+ init(container: PTRMapWidgetContainerView) {
90
+ self.container = container
91
+ }
92
+
93
+ func mapWidgetDidFinishLoading(_ mapWidget: PTRMapWidgetViewController, withError error: Error?) {
94
+ container?.ptrMapWidgetDidEndLoading(withParameters: ["error": error?.localizedDescription ?? ""])
95
+ }
96
+ }
79
97
 
80
98
  @objc func ptrMapWidgetDidEndLoading(withParameters parameters: [String: Any]) {
81
99
  onMapWidgetDidEndLoading?(parameters)
@@ -100,10 +118,14 @@ import PointrKit
100
118
  print("PTRMapWidget - initializing map widget")
101
119
  let mapWidget = PTRMapWidgetViewController(action: action, configuration: PTRNativeLibrary.mapWidgetConfiguration)
102
120
  self.mapWidget = mapWidget
103
- let adapter = WayfindingEventsAdapter(container: self, mapWidget: mapWidget)
104
- self.wayfindingEventsAdapter = adapter
105
- mapWidget.wayfindingEventsHandler = adapter
106
- mapWidget.addListener(self)
121
+ let wayfindingAdapter = WayfindingEventsAdapter(container: self, mapWidget: mapWidget)
122
+ self.wayfindingEventsAdapter = wayfindingAdapter
123
+ mapWidget.wayfindingEventsHandler = wayfindingAdapter
124
+ // Register the PTRMapWidgetEventsListener (loading + layout state) via a
125
+ // dedicated adapter because addListener short-circuits for that protocol.
126
+ let eventsAdapter = MapWidgetEventsAdapter(container: self)
127
+ self.mapWidgetEventsAdapter = eventsAdapter
128
+ mapWidget.addListener(eventsAdapter)
107
129
  return mapWidget
108
130
  }
109
131
 
@@ -119,127 +141,6 @@ import PointrKit
119
141
  ])
120
142
  }
121
143
 
122
- @objc func showStaticPath(_ siteExternalIdentifier: String,
123
- fromPoiExternalIdentifier: String,
124
- toPoiExternalIdentifier: String) {
125
- waitForPointrState()
126
-
127
- var ptrCommand: [String: Any] = [
128
- "command": "staticPath",
129
- "siteExternalIdentifier": siteExternalIdentifier,
130
- "fromPoiExternalIdentifier": fromPoiExternalIdentifier,
131
- "toPoiExternalIdentifier": toPoiExternalIdentifier
132
- ]
133
-
134
- guard let site = getSite(siteExternalIdentifier) else {
135
- ptrCommand["error"] = "Site not found"
136
- ptrMapWidgetDidEndLoading(withParameters: ptrCommand)
137
- print("no site found")
138
- return
139
- }
140
-
141
- guard let fromPoi = getPoi(site, poiExternalIdentifier: fromPoiExternalIdentifier) else {
142
- ptrCommand["error"] = "Source poi not found"
143
- ptrMapWidgetDidEndLoading(withParameters: ptrCommand)
144
- print("Source poi not found")
145
- return
146
- }
147
-
148
- guard let toPoi = getPoi(site, poiExternalIdentifier: toPoiExternalIdentifier) else {
149
- ptrCommand["error"] = "Target poi not found"
150
- ptrMapWidgetDidEndLoading(withParameters: ptrCommand)
151
- print("Destination poi not found")
152
- return
153
- }
154
-
155
- waitForPath(site)
156
-
157
- guard let pathManager = Pointr.shared.wayfindingManager else {
158
- ptrCommand["error"] = "Path manager not found"
159
- ptrMapWidgetDidEndLoading(withParameters: ptrCommand)
160
- print("Path manager not found")
161
- return
162
- }
163
-
164
- guard let route = pathManager.calculateRoute(fromPosition: fromPoi, toNearestPositionIn: [toPoi]) else {
165
- ptrCommand["error"] = "Path not found"
166
- ptrMapWidgetDidEndLoading(withParameters: ptrCommand)
167
- print("Path not found")
168
- return
169
- }
170
-
171
- let workItem = DispatchWorkItem { [weak self] in
172
- guard let self = self else { return }
173
-
174
- let location: PTRMapWidgetLocation
175
- if let level = fromPoi.position.level {
176
- location = PTRMapWidgetLevelLocation(
177
- siteIdentifier: site.identifier,
178
- buildingIdentifier: level.building.identifier,
179
- levelIndex: Int(level.index),
180
- isExternalIdentifiers: false
181
- )
182
- } else {
183
- location = PTRMapWidgetSiteLocation(
184
- siteIdentifier: site.identifier,
185
- isExternalIdentifiers: false
186
- )
187
- }
188
- let action = PTRMapWidgetMapFocusAction(location: location)
189
- let mapWidget = self.getMapWidget(action)
190
- action.completion = { [weak self, weak mapWidget] error in
191
- guard let self = self, let mapWidget = mapWidget else {
192
- ptrCommand["error"] = "Lost reference to PTRMapWidgetContainerView and/or PTRMapWidgetViewController"
193
- self?.ptrMapWidgetDidEndLoading(withParameters: ptrCommand)
194
- print("Error showing level: Lost reference to PTRMapWidgetContainerView and/or PTRMapWidgetViewController")
195
- return
196
- }
197
- if let error = error {
198
- ptrCommand["error"] = error.errorCode
199
- self.ptrMapWidgetDidEndLoading(withParameters: ptrCommand)
200
- print("Error showing level: \(error.errorCode ?? "")")
201
- return
202
- }
203
- self.setStaticPath(mapWidget.mapViewController, fromPoi: fromPoi, toPoi: toPoi, route: route)
204
- ptrCommand["error"] = ""
205
- self.ptrMapWidgetDidEndLoading(withParameters: ptrCommand)
206
- print("ready")
207
- }
208
- self.present(mapWidget)
209
- }
210
- DispatchQueue.main.async(execute: workItem)
211
- }
212
-
213
- func setStaticPath(_ map: PTRMapViewController, fromPoi: PTRPoi, toPoi: PTRPoi, route: PTRRoute) {
214
- let layer = PTRMapSymbolLayer(identifier: kLayerStaticPath)
215
- map.addLayer(layer)
216
- map.addFeatures([fromPoi, toPoi], toLayer: layer.identifier)
217
- map.currentRoute = route
218
- map.zoomToCoordinate(fromPoi.position.coordinate)
219
- }
220
-
221
- func waitForPath(_ site: PTRSite) {
222
- print("waiting for path to be ready")
223
- guard let pathManager = Pointr.shared.wayfindingManager else { return }
224
-
225
- self.site = site
226
- self.semaphore = DispatchSemaphore(value: 0)
227
- pathManager.addListener(self)
228
- if !pathManager.isReady(for: site) {
229
- let timeout = DispatchTime.now() + .seconds(5)
230
- if semaphore?.wait(timeout: timeout) == .timedOut {
231
- print("Timeout waiting for pathmanager")
232
- }
233
- }
234
- pathManager.removeListener(self)
235
- }
236
-
237
- func onWayfindingManagerReady(for site: PTRSite) {
238
- guard site.internalIdentifier == self.site?.internalIdentifier else { return }
239
- print("path became ready.")
240
- semaphore?.signal()
241
- }
242
-
243
144
  func getPoi(_ site: PTRSite, poiExternalIdentifier: String) -> PTRPoi? {
244
145
  guard let poiManager = Pointr.shared.poiManager else { return nil }
245
146
 
@@ -332,8 +233,8 @@ import PointrKit
332
233
 
333
234
  override func didMoveToWindow() {
334
235
  super.didMoveToWindow()
335
- guard window != nil, !commandDidExecute, let jsonString = pendingCommandString else { return }
336
- commandDidExecute = true
236
+ guard window != nil, !actionDidExecute, let jsonString = pendingActionString else { return }
237
+ actionDidExecute = true
337
238
  DispatchQueue.global(qos: .userInitiated).async { [weak self] in
338
239
  self?.executeCommandFromJSON(jsonString)
339
240
  }
@@ -393,78 +294,163 @@ import PointrKit
393
294
  let poiId = json["poi"] as? String ?? ""
394
295
  let fromPoiId = json["fromPoi"] as? String ?? ""
395
296
  let toPoiId = json["toPoi"] as? String ?? ""
396
- let sourcePoiId = json["sourcePoi"] as? String ?? ""
397
- let destinationPoiId = json["destinationPoi"] as? String ?? ""
398
297
 
399
298
  let action: PTRMapWidgetAction
400
299
  let commandParams: [String: Any]
401
300
 
402
301
  switch type {
403
- case "site":
404
- let location = PTRMapWidgetSiteLocation(siteIdentifier: siteId, isExternalIdentifiers: true)
405
- let focus = PTRMapWidgetMapFocusAction(location: location, completion: nil)
406
- commandParams = ["command": "site", "siteExternalIdentifier": siteId]
407
- focus.completion = { [weak self] error in
302
+ case "focusMap":
303
+ let location: PTRMapWidgetLocation
304
+ let params: [String: Any]
305
+ if !buildingId.isEmpty && json["level"] != nil {
306
+ location = PTRMapWidgetLevelLocation(
307
+ siteID: PTRIdentifier(siteId, isExternal: true),
308
+ buildingID: PTRIdentifier(buildingId, isExternal: true),
309
+ levelIndex: levelIndex
310
+ )
311
+ params = ["command": "focusMap", "siteExternalIdentifier": siteId, "buildingExternalIdentifier": buildingId, "levelIndex": levelIndex]
312
+ } else if !buildingId.isEmpty {
313
+ location = PTRMapWidgetBuildingLocation(
314
+ siteID: PTRIdentifier(siteId, isExternal: true),
315
+ buildingID: PTRIdentifier(buildingId, isExternal: true)
316
+ )
317
+ params = ["command": "focusMap", "siteExternalIdentifier": siteId, "buildingExternalIdentifier": buildingId]
318
+ } else {
319
+ location = PTRMapWidgetSiteLocation(siteID: PTRIdentifier(siteId, isExternal: true))
320
+ params = ["command": "focusMap", "siteExternalIdentifier": siteId]
321
+ }
322
+ commandParams = params
323
+ let focusAction = PTRMapWidgetAction.focusMap(location: location, completion: nil)
324
+ focusAction.completion = { [weak self] error in
408
325
  var p = commandParams; p["error"] = error?.errorCode ?? ""
409
326
  self?.ptrMapWidgetDidEndLoading(withParameters: p)
410
327
  }
411
- action = focus
328
+ action = focusAction
412
329
 
413
- case "building":
414
- let location = PTRMapWidgetBuildingLocation(siteIdentifier: siteId, buildingIdentifier: buildingId, isExternalIdentifiers: true)
415
- let focus = PTRMapWidgetMapFocusAction(location: location, completion: nil)
416
- commandParams = ["command": "building", "siteExternalIdentifier": siteId, "buildingExternalIdentifier": buildingId]
417
- focus.completion = { [weak self] error in
330
+ case "highlightPoi":
331
+ let hlLocation = PTRMapWidgetPoiLocation(
332
+ siteID: PTRIdentifier(siteId, isExternal: true),
333
+ poiID: PTRIdentifier(poiId, isExternal: true)
334
+ )
335
+ let hlAction = PTRMapWidgetAction.highlightPoi(location: hlLocation, completion: nil)
336
+ commandParams = ["command": "highlightPoi", "siteExternalIdentifier": siteId, "poiExternalIdentifier": poiId]
337
+ hlAction.completion = { [weak self] error in
418
338
  var p = commandParams; p["error"] = error?.errorCode ?? ""
419
339
  self?.ptrMapWidgetDidEndLoading(withParameters: p)
420
340
  }
421
- action = focus
341
+ action = hlAction
422
342
 
423
- case "level":
424
- let location = PTRMapWidgetLevelLocation(siteIdentifier: siteId, buildingIdentifier: buildingId, levelIndex: levelIndex, isExternalIdentifiers: true)
425
- let focus = PTRMapWidgetMapFocusAction(location: location, completion: nil)
426
- commandParams = ["command": "level", "siteExternalIdentifier": siteId, "buildingExternalIdentifier": buildingId, "levelIndex": levelIndex]
427
- focus.completion = { [weak self] error in
428
- var p = commandParams; p["error"] = error?.errorCode ?? ""
343
+ case "displayRoute":
344
+ // Display a static route between two specified POIs (no live location required)
345
+ let drSrc = PTRMapWidgetPoiLocation(
346
+ siteID: PTRIdentifier(siteId, isExternal: true),
347
+ poiID: PTRIdentifier(fromPoiId, isExternal: true)
348
+ )
349
+ let drDst = PTRMapWidgetPoiLocation(
350
+ siteID: PTRIdentifier(siteId, isExternal: true),
351
+ poiID: PTRIdentifier(toPoiId, isExternal: true)
352
+ )
353
+ let drAction = PTRMapWidgetAction.displayRoute(poiSource: drSrc, poiDestination: drDst, completion: nil)
354
+ commandParams = ["command": "displayRoute", "siteExternalIdentifier": siteId, "fromPoiExternalIdentifier": fromPoiId, "toPoiExternalIdentifier": toPoiId]
355
+ drAction.completion = { [weak self] error in
356
+ var p = commandParams; p["error"] = error?.localizedDescription ?? ""
429
357
  self?.ptrMapWidgetDidEndLoading(withParameters: p)
430
358
  }
431
- action = focus
359
+ action = drAction
432
360
 
433
- case "poi":
434
- let location = PTRMapWidgetPoiLocation(siteIdentifier: siteId, poiIdentifier: poiId, isExternalIdentifiers: true)
435
- let focus = PTRMapWidgetMapFocusAction(location: location, completion: nil)
436
- commandParams = ["command": "poi", "siteExternalIdentifier": siteId, "poiExternalIdentifier": poiId]
437
- focus.completion = { [weak self] error in
361
+ case "startWayfinding":
362
+ // Start live wayfinding from the user's current position to a destination POI
363
+ let swDst = PTRMapWidgetPoiLocation(
364
+ siteID: PTRIdentifier(siteId, isExternal: true),
365
+ poiID: PTRIdentifier(poiId, isExternal: true)
366
+ )
367
+ let swAction = PTRMapWidgetAction.startWayfinding(poi: swDst, completion: nil)
368
+ commandParams = ["command": "startWayfinding", "siteExternalIdentifier": siteId, "poiExternalIdentifier": poiId]
369
+ swAction.completion = { [weak self] error in
438
370
  var p = commandParams; p["error"] = error?.errorCode ?? ""
439
371
  self?.ptrMapWidgetDidEndLoading(withParameters: p)
440
372
  }
441
- action = focus
373
+ action = swAction
442
374
 
443
- case "path":
444
- let wayfinding = PTRMapWidgetWayfindingAction(poiDestination: PTRMapWidgetPoiLocation(siteIdentifier: siteId, poiIdentifier: poiId, isExternalIdentifiers: true))
445
- commandParams = ["command": "path", "siteExternalIdentifier": siteId, "poiExternalIdentifier": poiId]
446
- wayfinding.completion = { [weak self] error in
375
+ case "markMyCar":
376
+ let shouldShowPopup = json["shouldShowPopup"] as? Bool ?? true
377
+ let mmcAction: PTRMapWidgetAction
378
+ if !buildingId.isEmpty && json["level"] != nil {
379
+ let mmcLevel = PTRMapWidgetLevelLocation(
380
+ siteID: PTRIdentifier(siteId, isExternal: true),
381
+ buildingID: PTRIdentifier(buildingId, isExternal: true),
382
+ levelIndex: levelIndex
383
+ )
384
+ mmcAction = PTRMapWidgetAction.markMyCar(level: mmcLevel, shouldShowPopup: shouldShowPopup)
385
+ } else {
386
+ let mmcSite = PTRMapWidgetSiteLocation(siteID: PTRIdentifier(siteId, isExternal: true))
387
+ mmcAction = PTRMapWidgetAction.markMyCar(site: mmcSite, shouldShowPopup: shouldShowPopup)
388
+ }
389
+ commandParams = ["command": "markMyCar", "siteExternalIdentifier": siteId]
390
+ mmcAction.completion = { [weak self] error in
447
391
  var p = commandParams; p["error"] = error?.errorCode ?? ""
448
392
  self?.ptrMapWidgetDidEndLoading(withParameters: p)
449
393
  }
450
- action = wayfinding
394
+ action = mmcAction
451
395
 
452
- case "staticPath":
453
- DispatchQueue.global(qos: .default).async { [weak self] in
454
- self?.showStaticPath(siteId, fromPoiExternalIdentifier: fromPoiId, toPoiExternalIdentifier: toPoiId)
396
+ case "showMyCar":
397
+ let smcLoc = PTRMapWidgetSiteLocation(siteID: PTRIdentifier(siteId, isExternal: true))
398
+ let smcAction = PTRMapWidgetAction.showMyCar(location: smcLoc)
399
+ commandParams = ["command": "showMyCar", "siteExternalIdentifier": siteId]
400
+ smcAction.completion = { [weak self] error in
401
+ var p = commandParams; p["error"] = error?.errorCode ?? ""
402
+ self?.ptrMapWidgetDidEndLoading(withParameters: p)
455
403
  }
456
- return
404
+ action = smcAction
457
405
 
458
- case "staticWayfinding":
459
- let srcLocation = PTRMapWidgetPoiLocation(siteIdentifier: siteId, poiIdentifier: sourcePoiId, isExternalIdentifiers: true)
460
- let dstLocation = PTRMapWidgetPoiLocation(siteIdentifier: siteId, poiIdentifier: destinationPoiId, isExternalIdentifiers: true)
461
- let sw = PTRMapWidgetStaticWayfindingAction(poiSource: srcLocation, poiDestination: dstLocation)
462
- commandParams = ["command": "staticWayfinding", "siteExternalIdentifier": siteId, "sourcePoiExternalIdentifier": sourcePoiId, "destinationPoiExternalIdentifier": destinationPoiId]
463
- sw.completion = { [weak self] error in
464
- var p = commandParams; p["error"] = error?.localizedDescription ?? ""
406
+ case "focusCoordinate":
407
+ let lat = json["latitude"] as? Double ?? 0.0
408
+ let lon = json["longitude"] as? Double ?? 0.0
409
+ let lvl = json["levelIndex"] as? Int ?? -1
410
+ let coord = CLLocationCoordinate2D(latitude: lat, longitude: lon)
411
+ let coordLocation: PTRMapWidgetLocation
412
+ if lvl >= 0, !buildingId.isEmpty {
413
+ coordLocation = PTRMapWidgetLevelCoordinateLocation(
414
+ siteID: PTRIdentifier(siteId, isExternal: true),
415
+ buildingID: PTRIdentifier(buildingId, isExternal: true),
416
+ levelIndex: lvl,
417
+ coordinate: coord,
418
+ name: nil
419
+ )
420
+ } else {
421
+ coordLocation = PTRMapWidgetSiteCoordinateLocation(
422
+ siteID: PTRIdentifier(siteId, isExternal: true),
423
+ coordinate: coord,
424
+ name: nil
425
+ )
426
+ }
427
+ let coordAction = PTRMapWidgetAction.focusMap(location: coordLocation, completion: nil)
428
+ commandParams = ["command": "focusCoordinate", "siteExternalIdentifier": siteId]
429
+ coordAction.completion = { [weak self] error in
430
+ var p = commandParams; p["error"] = error?.errorCode ?? ""
465
431
  self?.ptrMapWidgetDidEndLoading(withParameters: p)
466
432
  }
467
- action = sw
433
+ action = coordAction
434
+
435
+ case "highlightCategory":
436
+ // Highlight a single category on the existing map widget.
437
+ // v10 SDK accepts a single category name (not an array of IDs).
438
+ let categoryName = (json["categoryIds"] as? [String])?.first ?? (json["category"] as? String ?? "")
439
+ commandParams = ["command": "highlightCategory", "siteExternalIdentifier": siteId]
440
+ waitForPointrState()
441
+ DispatchQueue.main.async { [weak self] in
442
+ guard let self = self else { return }
443
+ if let mapVC = self.mapWidget {
444
+ let catSite = PTRMapWidgetSiteLocation(siteID: PTRIdentifier(siteId, isExternal: true))
445
+ let catAction = PTRMapWidgetAction.highlightCategory(
446
+ name: categoryName,
447
+ site: catSite
448
+ )
449
+ mapVC.performAction(catAction)
450
+ }
451
+ self.ptrMapWidgetDidEndLoading(withParameters: commandParams)
452
+ }
453
+ return
468
454
 
469
455
  default:
470
456
  print("PTRMapWidget: unknown command type '\(type)'")
@@ -480,3 +466,4 @@ import PointrKit
480
466
  }
481
467
  }
482
468
 
469
+
@@ -13,16 +13,16 @@
13
13
 
14
14
  @interface RCT_EXTERN_MODULE(PTRMapWidgetManager, RCTViewManager)
15
15
 
16
+ // ─── View event props ───────────────────────────────────────────────────────
16
17
  RCT_EXPORT_VIEW_PROPERTY(onMapWidgetDidEndLoading, RCTBubblingEventBlock)
17
-
18
18
  RCT_EXPORT_VIEW_PROPERTY(onWayfindingEvent, RCTBubblingEventBlock)
19
19
 
20
- RCT_EXPORT_VIEW_PROPERTY(command, NSString)
21
-
20
+ // ─── Config props ────────────────────────────────────────────────────────────
21
+ RCT_EXPORT_VIEW_PROPERTY(action, NSString)
22
22
  RCT_EXPORT_VIEW_PROPERTY(sdkConfig, NSString)
23
-
24
23
  RCT_EXPORT_VIEW_PROPERTY(mapWidgetConfig, NSString)
25
24
 
25
+ // ─── Imperative commands ─────────────────────────────────────────────────────
26
26
  RCT_EXTERN_METHOD(site:(nonnull NSNumber *)reactTag
27
27
  siteExternalIdentifier:(NSString *)siteExternalIdentifier)
28
28
  RCT_EXTERN_METHOD(building:(nonnull NSNumber *)reactTag
@@ -38,16 +38,11 @@ RCT_EXTERN_METHOD(poi:(nonnull NSNumber *)reactTag
38
38
  siteExternalIdentifier:(NSString *)siteExternalIdentifier
39
39
  poiExternalIdentifier:(NSString *)poiExternalIdentifier)
40
40
 
41
- RCT_EXTERN_METHOD(path:(nonnull NSNumber *)reactTag
41
+ RCT_EXTERN_METHOD(startWayfinding:(nonnull NSNumber *)reactTag
42
42
  siteExternalIdentifier:(NSString *)siteExternalIdentifier
43
43
  toPoiExternalIdentifier:(NSString *)toPoiExternalIdentifier)
44
44
 
45
- RCT_EXTERN_METHOD(staticPath:(nonnull NSNumber *)reactTag
46
- siteExternalIdentifier:(NSString *)siteExternalIdentifier
47
- fromPoiExternalIdentifier:(NSString *)fromPoiExternalIdentifier
48
- toPoiExternalIdentifier:(NSString *)toPoiExternalIdentifier)
49
-
50
- RCT_EXTERN_METHOD(staticWayfinding:(nonnull NSNumber *)reactTag
45
+ RCT_EXTERN_METHOD(displayRoute:(nonnull NSNumber *)reactTag
51
46
  siteExternalIdentifier:(NSString *)siteExternalIdentifier
52
47
  sourcePoiExternalIdentifier:(NSString *)sourcePoiExternalIdentifier
53
48
  destinationPoiExternalIdentifier:(NSString *)destinationPoiExternalIdentifier)
@@ -68,62 +63,15 @@ RCT_EXTERN_METHOD(myCarForSite:(nonnull NSNumber *)reactTag
68
63
  siteExternalIdentifier:(NSString *)siteExternalIdentifier
69
64
  animationType:(NSInteger)animationType)
70
65
 
71
- RCT_EXTERN_METHOD(startAndFocus:(nonnull NSNumber *)reactTag
72
- clientId:(NSString *)clientId
73
- licenseKey:(NSString *)licenseKey
74
- baseUrl:(NSString *)baseUrl
75
- logLevel:(NSInteger)logLevel
76
- focusType:(nonnull NSString *)focusType
77
- siteExternalIdentifier:(NSString *)siteExternalIdentifier
78
- )
79
-
80
- RCT_EXTERN_METHOD(startAndFocus:(nonnull NSNumber *)reactTag
81
- clientId:(NSString *)clientId
82
- licenseKey:(NSString *)licenseKey
83
- baseUrl:(NSString *)baseUrl
84
- focusType:(nonnull NSString *)focusType
66
+ RCT_EXTERN_METHOD(coordinate:(nonnull NSNumber *)reactTag
85
67
  siteExternalIdentifier:(NSString *)siteExternalIdentifier
86
- )
87
-
88
- RCT_EXTERN_METHOD(startAndFocus:(nonnull NSNumber *)reactTag
89
- clientId:(NSString *)clientId
90
- licenseKey:(NSString *)licenseKey
91
- baseUrl:(NSString *)baseUrl
92
- focusType:(nonnull NSString *)focusType
93
- siteExternalIdentifier:(NSString *)siteExternalIdentifier
94
- param1:(NSString *)param1
95
- )
96
-
97
- RCT_EXTERN_METHOD(startAndFocus:(nonnull NSNumber *)reactTag
98
- clientId:(NSString *)clientId
99
- licenseKey:(NSString *)licenseKey
100
- baseUrl:(NSString *)baseUrl
101
- focusType:(nonnull NSString *)focusType
102
- siteExternalIdentifier:(NSString *)siteExternalIdentifier
103
- param1:(NSString *)param1
104
- levelIndex:(NSInteger)levelIndex
105
- )
68
+ latitude:(double)latitude
69
+ longitude:(double)longitude
70
+ levelIndex:(NSInteger)levelIndex)
106
71
 
107
- RCT_EXTERN_METHOD(startAndFocus:(nonnull NSNumber *)reactTag
108
- clientId:(NSString *)clientId
109
- licenseKey:(NSString *)licenseKey
110
- baseUrl:(NSString *)baseUrl
111
- logLevel:(NSInteger)logLevel
112
- focusType:(nonnull NSString *)focusType
72
+ RCT_EXTERN_METHOD(highlightCategory:(nonnull NSNumber *)reactTag
113
73
  siteExternalIdentifier:(NSString *)siteExternalIdentifier
114
- param1:(NSString *)param1
115
- )
74
+ categoryIds:(NSArray *)categoryIds)
116
75
 
117
- RCT_EXTERN_METHOD(startAndFocus:(nonnull NSNumber *)reactTag
118
- clientId:(NSString *)clientId
119
- licenseKey:(NSString *)licenseKey
120
- baseUrl:(NSString *)baseUrl
121
- logLevel:(NSInteger)logLevel
122
- focusType:(nonnull NSString *)focusType
123
- siteExternalIdentifier:(NSString *)siteExternalIdentifier
124
- param1:(NSString *)param1
125
- levelIndex:(NSInteger)levelIndex
126
- )
127
76
  @end
128
77
 
129
- // No additional methods are needed here as the PTRMapWidgetManager is implemented in Objective-C