@rematter/pylon-react-native 0.1.4 → 0.1.5

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.
@@ -14,61 +14,61 @@ import WebKit
14
14
  // Note: PylonChat files will be added to Xcode project from ../../ios/PylonChat/
15
15
 
16
16
  class RNPylonChatView: UIView {
17
-
17
+
18
18
  private var pylonChatView: PylonChatView?
19
19
  private var config: PylonConfig?
20
20
  private var user: PylonUser?
21
-
21
+
22
22
  // Config properties
23
23
  @objc var appId: NSString = "" {
24
24
  didSet { updateConfig() }
25
25
  }
26
-
26
+
27
27
  @objc var widgetBaseUrl: NSString? {
28
28
  didSet { updateConfig() }
29
29
  }
30
-
30
+
31
31
  @objc var widgetScriptUrl: NSString? {
32
32
  didSet { updateConfig() }
33
33
  }
34
-
34
+
35
35
  @objc var enableLogging: Bool = true {
36
36
  didSet { updateConfig() }
37
37
  }
38
-
38
+
39
39
  @objc var debugMode: Bool = false {
40
40
  didSet { updateConfig() }
41
41
  }
42
-
42
+
43
43
  @objc var primaryColor: NSString? {
44
44
  didSet { updateConfig() }
45
45
  }
46
-
46
+
47
47
  // User properties
48
48
  @objc var userEmail: NSString? {
49
49
  didSet { updateUser() }
50
50
  }
51
-
51
+
52
52
  @objc var userName: NSString? {
53
53
  didSet { updateUser() }
54
54
  }
55
-
55
+
56
56
  @objc var userAvatarUrl: NSString? {
57
57
  didSet { updateUser() }
58
58
  }
59
-
59
+
60
60
  @objc var userEmailHash: NSString? {
61
61
  didSet { updateUser() }
62
62
  }
63
-
63
+
64
64
  @objc var userAccountId: NSString? {
65
65
  didSet { updateUser() }
66
66
  }
67
-
67
+
68
68
  @objc var userAccountExternalId: NSString? {
69
69
  didSet { updateUser() }
70
70
  }
71
-
71
+
72
72
  // Safe area top inset for coordinate space adjustment
73
73
  @objc var topInset: NSNumber = 0 {
74
74
  didSet {
@@ -77,7 +77,7 @@ class RNPylonChatView: UIView {
77
77
  }
78
78
  }
79
79
  }
80
-
80
+
81
81
  // Event callbacks - renamed to avoid collision with PylonChatListener methods
82
82
  @objc var rctOnPylonLoaded: RCTBubblingEventBlock?
83
83
  @objc var rctOnPylonInitialized: RCTBubblingEventBlock?
@@ -87,28 +87,28 @@ class RNPylonChatView: UIView {
87
87
  @objc var rctOnUnreadCountChanged: RCTBubblingEventBlock?
88
88
  @objc var rctOnMessageReceived: RCTBubblingEventBlock?
89
89
  @objc var rctOnPylonError: RCTBubblingEventBlock?
90
-
90
+
91
91
  override init(frame: CGRect) {
92
92
  super.init(frame: frame)
93
93
  setupView()
94
94
  }
95
-
95
+
96
96
  required init?(coder: NSCoder) {
97
97
  super.init(coder: coder)
98
98
  setupView()
99
99
  }
100
-
100
+
101
101
  private func setupView() {
102
102
  backgroundColor = .clear
103
103
  }
104
-
104
+
105
105
  // Override pointInside to make React Native call hitTest
106
106
  public override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
107
107
  // Always return true so React Native will call hitTest
108
108
  // The actual hit detection happens in hitTest
109
109
  return true
110
110
  }
111
-
111
+
112
112
  // Forward hit testing to the embedded PylonChatView
113
113
  public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
114
114
  // If we have a PylonChatView, let it handle hit testing
@@ -117,14 +117,14 @@ class RNPylonChatView: UIView {
117
117
  let convertedPoint = convert(point, to: pylonView)
118
118
  return pylonView.hitTest(convertedPoint, with: event)
119
119
  }
120
-
120
+
121
121
  // If no PylonChatView yet, pass through (return nil)
122
122
  return nil
123
123
  }
124
-
124
+
125
125
  private func updateConfig() {
126
126
  guard (appId as String).isEmpty == false else { return }
127
-
127
+
128
128
  config = PylonConfig(
129
129
  appId: appId as String,
130
130
  enableLogging: enableLogging,
@@ -133,14 +133,14 @@ class RNPylonChatView: UIView {
133
133
  widgetBaseUrl: widgetBaseUrl as String?,
134
134
  widgetScriptUrl: widgetScriptUrl as String?
135
135
  )
136
-
136
+
137
137
  recreatePylonView()
138
138
  }
139
-
139
+
140
140
  private func updateUser() {
141
141
  guard let email = userEmail as String?,
142
142
  let name = userName as String? else { return }
143
-
143
+
144
144
  user = PylonUser(
145
145
  email: email,
146
146
  name: name,
@@ -149,75 +149,75 @@ class RNPylonChatView: UIView {
149
149
  accountId: userAccountId as String?,
150
150
  accountExternalId: userAccountExternalId as String?
151
151
  )
152
-
152
+
153
153
  recreatePylonView()
154
154
  }
155
-
155
+
156
156
  private func recreatePylonView() {
157
157
  guard let config = config, let user = user else { return }
158
-
158
+
159
159
  // Remove old view
160
160
  pylonChatView?.removeFromSuperview()
161
-
161
+
162
162
  // Create new PylonChatView
163
163
  let newView = PylonChatView(config: config, user: user)
164
164
  newView.listener = self
165
165
  newView.topInset = CGFloat(truncating: topInset)
166
166
  newView.translatesAutoresizingMaskIntoConstraints = false
167
-
167
+
168
168
  addSubview(newView)
169
-
169
+
170
170
  NSLayoutConstraint.activate([
171
171
  newView.topAnchor.constraint(equalTo: topAnchor),
172
172
  newView.leadingAnchor.constraint(equalTo: leadingAnchor),
173
173
  newView.trailingAnchor.constraint(equalTo: trailingAnchor),
174
174
  newView.bottomAnchor.constraint(equalTo: bottomAnchor)
175
175
  ])
176
-
176
+
177
177
  pylonChatView = newView
178
-
178
+
179
179
  // Force layout
180
180
  setNeedsLayout()
181
181
  layoutIfNeeded()
182
182
  }
183
-
183
+
184
184
  // Imperative methods (called from React Native)
185
185
  func openChat() {
186
186
  pylonChatView?.openChat()
187
187
  }
188
-
188
+
189
189
  func closeChat() {
190
190
  pylonChatView?.closeChat()
191
191
  }
192
-
192
+
193
193
  func showChatBubble() {
194
194
  pylonChatView?.showChatBubble()
195
195
  }
196
-
196
+
197
197
  func hideChatBubble() {
198
198
  pylonChatView?.hideChatBubble()
199
199
  }
200
-
200
+
201
201
  func showNewMessage(_ message: String, isHtml: Bool) {
202
202
  pylonChatView?.showNewMessage(message, isHtml: isHtml)
203
203
  }
204
-
204
+
205
205
  func setNewIssueCustomFields(_ fields: [String: Any]) {
206
206
  pylonChatView?.setNewIssueCustomFields(fields)
207
207
  }
208
-
208
+
209
209
  func setTicketFormFields(_ fields: [String: Any]) {
210
210
  pylonChatView?.setTicketFormFields(fields)
211
211
  }
212
-
212
+
213
213
  func updateEmailHash(_ emailHash: String?) {
214
214
  pylonChatView?.updateEmailHash(emailHash)
215
215
  }
216
-
216
+
217
217
  func showTicketForm(_ slug: String) {
218
218
  pylonChatView?.showTicketForm(slug)
219
219
  }
220
-
220
+
221
221
  func showKnowledgeBaseArticle(_ articleId: String) {
222
222
  pylonChatView?.showKnowledgeBaseArticle(articleId)
223
223
  }
@@ -228,31 +228,31 @@ extension RNPylonChatView: PylonChatListener {
228
228
  func onPylonLoaded() {
229
229
  rctOnPylonLoaded?([:])
230
230
  }
231
-
231
+
232
232
  func onPylonInitialized() {
233
233
  rctOnPylonInitialized?([:])
234
234
  }
235
-
235
+
236
236
  func onPylonReady() {
237
237
  rctOnPylonReady?([:])
238
238
  }
239
-
239
+
240
240
  func onMessageReceived(message: String) {
241
241
  rctOnMessageReceived?(["message": message])
242
242
  }
243
-
243
+
244
244
  func onChatOpened() {
245
245
  rctOnChatOpened?([:])
246
246
  }
247
-
247
+
248
248
  func onChatClosed(wasOpen: Bool) {
249
249
  rctOnChatClosed?(["wasOpen": wasOpen])
250
250
  }
251
-
251
+
252
252
  func onPylonError(error: String) {
253
253
  rctOnPylonError?(["error": error])
254
254
  }
255
-
255
+
256
256
  func onUnreadCountChanged(count: Int) {
257
257
  rctOnUnreadCountChanged?(["count": count])
258
258
  }
@@ -261,71 +261,90 @@ extension RNPylonChatView: PylonChatListener {
261
261
  // MARK: - Imperative method helpers
262
262
  extension RNPylonChatViewManager {
263
263
  @objc func openChat(_ reactTag: NSNumber) {
264
- bridge.uiManager.addUIBlock { _, viewRegistry in
265
- guard let view = viewRegistry?[reactTag] as? RNPylonChatView else { return }
264
+ self.bridge.uiManager.addUIBlock { uiManager, viewRegistry in
265
+ // Use uiManager.view(forReactTag:) instead of viewRegistry
266
+ guard let uiManager = uiManager else {
267
+ print("⚠️ RNPylonChat: uiManager is nil")
268
+ return
269
+ }
270
+
271
+ guard let view = uiManager.view(forReactTag: reactTag) as? RNPylonChatView else {
272
+ print("⚠️ RNPylonChat: Could not find view for reactTag: \(reactTag)")
273
+ return
274
+ }
275
+
266
276
  view.openChat()
267
277
  }
268
278
  }
269
-
279
+
270
280
  @objc func closeChat(_ reactTag: NSNumber) {
271
- bridge.uiManager.addUIBlock { _, viewRegistry in
272
- guard let view = viewRegistry?[reactTag] as? RNPylonChatView else { return }
281
+ self.bridge.uiManager.addUIBlock { uiManager, _ in
282
+ guard let uiManager = uiManager,
283
+ let view = uiManager.view(forReactTag: reactTag) as? RNPylonChatView else { return }
273
284
  view.closeChat()
274
285
  }
275
286
  }
276
-
287
+
277
288
  @objc func showChatBubble(_ reactTag: NSNumber) {
278
- bridge.uiManager.addUIBlock { _, viewRegistry in
279
- guard let view = viewRegistry?[reactTag] as? RNPylonChatView else { return }
289
+ self.bridge.uiManager.addUIBlock { uiManager, _ in
290
+ guard let uiManager = uiManager,
291
+ let view = uiManager.view(forReactTag: reactTag) as? RNPylonChatView else { return }
280
292
  view.showChatBubble()
281
293
  }
282
294
  }
283
-
295
+
284
296
  @objc func hideChatBubble(_ reactTag: NSNumber) {
285
- bridge.uiManager.addUIBlock { _, viewRegistry in
286
- guard let view = viewRegistry?[reactTag] as? RNPylonChatView else { return }
297
+ self.bridge.uiManager.addUIBlock { uiManager, _ in
298
+ guard let uiManager = uiManager,
299
+ let view = uiManager.view(forReactTag: reactTag) as? RNPylonChatView else { return }
287
300
  view.hideChatBubble()
288
301
  }
289
302
  }
290
-
303
+
291
304
  @objc func showNewMessage(_ reactTag: NSNumber, message: NSString, isHtml: Bool) {
292
- bridge.uiManager.addUIBlock { _, viewRegistry in
293
- guard let view = viewRegistry?[reactTag] as? RNPylonChatView else { return }
305
+ self.bridge.uiManager.addUIBlock { uiManager, _ in
306
+ guard let uiManager = uiManager,
307
+ let view = uiManager.view(forReactTag: reactTag) as? RNPylonChatView else { return }
294
308
  view.showNewMessage(message as String, isHtml: isHtml)
295
309
  }
296
310
  }
297
-
311
+
298
312
  @objc func setNewIssueCustomFields(_ reactTag: NSNumber, fields: NSDictionary) {
299
- bridge.uiManager.addUIBlock { _, viewRegistry in
300
- guard let view = viewRegistry?[reactTag] as? RNPylonChatView else { return }
313
+ self.bridge.uiManager.addUIBlock { uiManager, _ in
314
+ guard let uiManager = uiManager,
315
+ let view = uiManager.view(forReactTag: reactTag) as? RNPylonChatView else { return }
301
316
  view.setNewIssueCustomFields(fields as! [String: Any])
302
317
  }
303
318
  }
304
-
319
+
305
320
  @objc func setTicketFormFields(_ reactTag: NSNumber, fields: NSDictionary) {
306
- bridge.uiManager.addUIBlock { _, viewRegistry in
307
- guard let view = viewRegistry?[reactTag] as? RNPylonChatView else { return }
321
+ self.bridge.uiManager.addUIBlock { uiManager, _ in
322
+ guard let uiManager = uiManager,
323
+ let view = uiManager.view(forReactTag: reactTag) as? RNPylonChatView else { return }
308
324
  view.setTicketFormFields(fields as! [String: Any])
309
325
  }
310
326
  }
311
-
327
+
312
328
  @objc func updateEmailHash(_ reactTag: NSNumber, emailHash: NSString?) {
313
- bridge.uiManager.addUIBlock { _, viewRegistry in
314
- guard let view = viewRegistry?[reactTag] as? RNPylonChatView else { return }
329
+ self.bridge.uiManager.addUIBlock { uiManager, _ in
330
+ guard let uiManager = uiManager,
331
+ let view = uiManager.view(forReactTag: reactTag) as? RNPylonChatView else { return }
315
332
  view.updateEmailHash(emailHash as String?)
316
333
  }
317
334
  }
318
-
335
+
319
336
  @objc func showTicketForm(_ reactTag: NSNumber, slug: NSString) {
320
- bridge.uiManager.addUIBlock { _, viewRegistry in
321
- guard let view = viewRegistry?[reactTag] as? RNPylonChatView else { return }
337
+ self.bridge.uiManager.addUIBlock { uiManager, _ in
338
+ guard let uiManager = uiManager,
339
+ let view = uiManager.view(forReactTag: reactTag) as? RNPylonChatView else { return }
322
340
  view.showTicketForm(slug as String)
323
341
  }
324
342
  }
325
-
343
+
326
344
  @objc func showKnowledgeBaseArticle(_ reactTag: NSNumber, articleId: NSString) {
327
- bridge.uiManager.addUIBlock { _, viewRegistry in
328
- guard let view = viewRegistry?[reactTag] as? RNPylonChatView else { return }
345
+ self.bridge.uiManager.addUIBlock { uiManager, _ in
346
+ guard let uiManager = uiManager,
347
+ let view = uiManager.view(forReactTag: reactTag) as? RNPylonChatView else { return }
329
348
  view.showKnowledgeBaseArticle(articleId as String)
330
349
  }
331
350
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rematter/pylon-react-native",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Pylon Chat SDK for React Native",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",