rn-erxes-sdk 0.2.5 → 0.3.2

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/README.md CHANGED
@@ -85,16 +85,46 @@ erxes is composed of 2 main components: **XOS** & **Plugins**
85
85
  - **Knowledgebase** - Educate your customers and staff by creating a help center related to your brands, products, and services to reach a higher level of satisfaction.
86
86
  - **Task Management** - Create a more collaborative, self-reliant and cross-linked team. **<a href="https://erxes.io/marketplace" >See more on our website</a>**.
87
87
 
88
- ## Usage
88
+ ## Screenshots
89
+
90
+ ### iOS ✅ Available
91
+
92
+ Screenshots from the native [`erxes/erxes-ios-sdk`](https://github.com/erxes/erxes-ios-sdk).
89
93
 
90
- <img src="https://raw.githubusercontent.com/erxes/rn-erxes-sdk/main/MOBILE-SDK.png" alt="rn-erxes-sdk messenger screenshot" width="350">
94
+ **Classic mode** (`displayMode: 'classic'`)
95
+
96
+ <p align="center">
97
+ <img src="https://raw.githubusercontent.com/erxes/erxes-ios-sdk/main/screenshots/home.png" width="220" alt="Home">
98
+ <img src="https://raw.githubusercontent.com/erxes/erxes-ios-sdk/main/screenshots/messages.png" width="220" alt="Messages">
99
+ <img src="https://raw.githubusercontent.com/erxes/erxes-ios-sdk/main/screenshots/tickets.png" width="220" alt="Tickets">
100
+ </p>
101
+
102
+ **Chat mode** (`displayMode: 'chat'`)
103
+
104
+ <p align="center">
105
+ <img src="https://raw.githubusercontent.com/erxes/erxes-ios-sdk/main/screenshots/new-chat.png" width="220" alt="New Chat">
106
+ <img src="https://raw.githubusercontent.com/erxes/erxes-ios-sdk/main/screenshots/recent-chats.png" width="220" alt="Recent Chats">
107
+ </p>
108
+
109
+ ### Android 🚧 Upcoming
110
+
111
+ _Coming soon._
112
+
113
+ > **Platform support:** iOS is fully supported (native SwiftUI messenger). Android support is on the roadmap — see the [TODO](#roadmap) below.
114
+
115
+ ## Roadmap
116
+
117
+ - [x] iOS native messenger (classic widget + chat mode)
118
+ - [ ] Android native messenger
91
119
 
92
120
  ---
93
121
 
94
122
  # rn-erxes-sdk
95
123
 
96
124
  A React Native bridge for the native SwiftUI erxes messenger
97
- ([`erxes/erxes-ios-sdk`](https://github.com/erxes/erxes-ios-sdk) `0.30.0`).
125
+ ([`erxes/erxes-ios-sdk`](https://github.com/erxes/erxes-ios-sdk) `0.30.7`).
126
+ Supports the classic widget and the full-screen **chat mode** (with voice
127
+ messages and header/drawer actions).
98
128
 
99
129
  ```tsx
100
130
  import { ErxesNativeIOS } from 'rn-erxes-sdk';
@@ -184,6 +214,29 @@ If you have a custom trigger in your UI, call `showMessenger()` directly:
184
214
  <Button title="Support" onPress={() => ErxesNativeIOS.showMessenger()} />
185
215
  ```
186
216
 
217
+ ### Chat mode
218
+
219
+ Pass `displayMode: 'chat'` for the full-screen assistant shell (it auto-opens
220
+ when connected, so `showLauncher()` is a no-op). You can add header/drawer
221
+ actions and react to taps by `id`:
222
+
223
+ ```tsx
224
+ ErxesNativeIOS.configure({
225
+ integrationId: 'YOUR_INTEGRATION_ID',
226
+ subDomain: 'yourcompany.erxes.io',
227
+ displayMode: 'chat',
228
+ homeActions: [{ id: 'orders', title: 'My Orders', systemIcon: 'bag' }],
229
+ drawerActions: [{ id: 'settings', title: 'Settings', systemIcon: 'gearshape' }],
230
+ });
231
+
232
+ const sub = ErxesNativeIOS.addActionListener((id) => {
233
+ // navigate / open a modal based on id
234
+ });
235
+ // sub.remove() on cleanup
236
+ ```
237
+
238
+ Chat mode also supports voice messages — see the [Native iOS guide](docs/native-ios.md) for the required `Info.plist` permissions.
239
+
187
240
  On logout:
188
241
 
189
242
  ```tsx
@@ -254,25 +307,6 @@ yarn install
254
307
  npx expo start --clear
255
308
  ```
256
309
 
257
- ### Release
258
-
259
- ```bash
260
- npm login
261
- npm whoami
262
-
263
- npm version patch
264
- npm publish
265
-
266
- npm view rn-erxes-sdk version
267
- git push origin main --follow-tags
268
- ```
269
-
270
- - Pushing to GitHub does **not** publish to npm.
271
- - npmjs displays the README from the **published** package version.
272
- - Each release requires a new version; a published version cannot be republished.
273
- - `npm version patch` is appropriate for backward-compatible fixes and documentation updates.
274
- - `npm publish` may require 2FA or a granular access token with publish permission.
275
- - Do not repeatedly run `npm version patch` after a failed publish unless a genuinely new version is needed.
276
310
  ## Become a partner
277
311
 
278
312
  Offer your expertise to the world and introduce your community to erxes.
@@ -1,7 +1,7 @@
1
1
  # Native iOS Guide
2
2
 
3
3
  `ErxesNativeIOS` bridges the native SwiftUI erxes messenger
4
- ([`erxes/erxes-ios-sdk`](https://github.com/erxes/erxes-ios-sdk) `0.30.0`)
4
+ ([`erxes/erxes-ios-sdk`](https://github.com/erxes/erxes-ios-sdk) `0.30.7`)
5
5
  into your React Native app.
6
6
 
7
7
  ## Requirements
@@ -119,6 +119,104 @@ ErxesNativeIOS.configure({ integrationId, subDomain });
119
119
 
120
120
  ---
121
121
 
122
+ ## Chat mode (`displayMode: 'chat'`)
123
+
124
+ Set `displayMode: 'chat'` to present an AI-assistant-style full-screen shell
125
+ instead of the classic 4-tab sheet widget. In chat mode the messenger opens
126
+ **itself** full-screen as soon as the connect handshake succeeds — there is no
127
+ floating launcher, so `showLauncher()` is a no-op (the messenger is already up).
128
+ Omit `displayMode` (or pass `'classic'`) to keep the classic widget.
129
+
130
+ ### Header / drawer actions
131
+
132
+ Chat mode can render host-configurable actions in the header (`homeActions`) and
133
+ the left drawer (`drawerActions`). Actions cross the JS↔native bridge as **plain
134
+ data** (`id`, `title`, `systemIcon`) — never as functions. Tapping an action
135
+ fires a single native event carrying just the tapped `id`; your JS code decides
136
+ what happens (navigate, open a modal, etc.) by switching on that `id`.
137
+
138
+ Use `ErxesNativeIOS.addActionListener` to subscribe — it returns a subscription
139
+ you `.remove()` on cleanup.
140
+
141
+ ```tsx
142
+ import { useEffect } from 'react';
143
+ import { useNavigation } from '@react-navigation/native';
144
+ import { ErxesNativeIOS } from 'rn-erxes-sdk';
145
+
146
+ function App() {
147
+ const navigation = useNavigation();
148
+
149
+ useEffect(() => {
150
+ // 1. Configure with data-only action descriptors (id/title/icon — no functions)
151
+ ErxesNativeIOS.configure({
152
+ integrationId: 'YOUR_INTEGRATION_ID',
153
+ subDomain: 'yourcompany.erxes.io',
154
+ displayMode: 'chat',
155
+ homeActions: [
156
+ { id: 'orders', title: 'My Orders', systemIcon: 'bag' },
157
+ { id: 'profile', title: 'Profile', systemIcon: 'person' },
158
+ ],
159
+ drawerActions: [
160
+ { id: 'settings', title: 'Settings', systemIcon: 'gearshape' },
161
+ ],
162
+ });
163
+
164
+ // 2. Listen for taps — native only ever sends the id back
165
+ const sub = ErxesNativeIOS.addActionListener((id) => {
166
+ switch (id) {
167
+ case 'orders':
168
+ navigation.navigate('Orders');
169
+ break;
170
+ case 'profile':
171
+ navigation.navigate('Profile');
172
+ break;
173
+ case 'settings':
174
+ openSettingsModal(); // your own modal trigger
175
+ break;
176
+ }
177
+ });
178
+
179
+ return () => sub.remove();
180
+ }, [navigation]);
181
+
182
+ return null;
183
+ }
184
+ ```
185
+
186
+ `systemIcon` is an [SF Symbol](https://developer.apple.com/sf-symbols/) name
187
+ (e.g. `"bag"`, `"gearshape"`).
188
+
189
+ ---
190
+
191
+ ## Voice messages
192
+
193
+ In chat mode the messenger supports **voice messages** (audio playback) and
194
+ **speech-to-text** dictation in the composer. These use the microphone and speech
195
+ recognition, so your host app must declare the matching usage descriptions in its
196
+ `Info.plist`:
197
+
198
+ ```xml
199
+ <key>NSMicrophoneUsageDescription</key>
200
+ <string>Record voice messages in support chat.</string>
201
+ <key>NSSpeechRecognitionUsageDescription</key>
202
+ <string>Transcribe your voice into chat messages.</string>
203
+ ```
204
+
205
+ For Expo, add them under `ios.infoPlist` in `app.json`:
206
+
207
+ ```json
208
+ {
209
+ "ios": {
210
+ "infoPlist": {
211
+ "NSMicrophoneUsageDescription": "Record voice messages in support chat.",
212
+ "NSSpeechRecognitionUsageDescription": "Transcribe your voice into chat messages."
213
+ }
214
+ }
215
+ }
216
+ ```
217
+
218
+ ---
219
+
122
220
  ## Logout
123
221
 
124
222
  Clear the user when they log out of your app:
package/ios/RnErxesSdk.m CHANGED
@@ -1,6 +1,7 @@
1
1
  #import <React/RCTBridgeModule.h>
2
+ #import <React/RCTEventEmitter.h>
2
3
 
3
- @interface RCT_EXTERN_MODULE(RnErxesSdk, NSObject)
4
+ @interface RCT_EXTERN_MODULE(RnErxesSdk, RCTEventEmitter)
4
5
 
5
6
  RCT_EXTERN_METHOD(configure:(NSDictionary *)options
6
7
  resolver:(RCTPromiseResolveBlock)resolve
@@ -4,12 +4,29 @@ import UIKit
4
4
  import React
5
5
 
6
6
  @objc(RnErxesSdk)
7
- final class RnErxesSdk: NSObject {
8
- @objc
9
- static func requiresMainQueueSetup() -> Bool {
7
+ final class RnErxesSdk: RCTEventEmitter {
8
+ /// JS event fired when a chat-mode action (homeActions/drawerActions) is tapped.
9
+ private static let actionEvent = "onErxesAction"
10
+
11
+ /// True while JS has at least one listener attached, so we don't emit into the void.
12
+ private var hasListeners = false
13
+
14
+ override static func requiresMainQueueSetup() -> Bool {
10
15
  true
11
16
  }
12
17
 
18
+ override func supportedEvents() -> [String] {
19
+ [Self.actionEvent]
20
+ }
21
+
22
+ override func startObserving() {
23
+ hasListeners = true
24
+ }
25
+
26
+ override func stopObserving() {
27
+ hasListeners = false
28
+ }
29
+
13
30
  @objc(configure:resolver:rejecter:)
14
31
  func configure(
15
32
  _ options: NSDictionary,
@@ -28,12 +45,32 @@ final class RnErxesSdk: NSObject {
28
45
  }
29
46
 
30
47
  let cachedCustomerId = Self.string(options["cachedCustomerId"])
48
+ let displayMode = Self.string(options["displayMode"])
49
+ .flatMap(DisplayMode.init(rawValue:)) ?? .classic
50
+ let homeActions = Self.actionItems(options["homeActions"])
51
+ let drawerActions = Self.actionItems(options["drawerActions"])
52
+
53
+ var appearance = MessengerConfig.Appearance()
54
+ if let primaryColor = Self.hexColor(options["primaryColor"]) {
55
+ appearance.primaryColor = primaryColor
56
+ }
57
+
58
+ // Route chat-mode action taps to JS as `onErxesAction` events. The SDK
59
+ // only hands back the tapped action's id (data-only across the bridge).
60
+ MessengerSDK.shared.onAction = { [weak self] id in
61
+ guard let self, self.hasListeners else { return }
62
+ self.sendEvent(withName: Self.actionEvent, body: ["id": id])
63
+ }
31
64
 
32
65
  MessengerSDK.configure(
33
66
  MessengerConfig(
34
67
  endpoint: endpoint,
35
68
  integrationId: integrationId,
36
- cachedCustomerId: cachedCustomerId
69
+ cachedCustomerId: cachedCustomerId,
70
+ appearance: appearance,
71
+ displayMode: displayMode,
72
+ homeActions: homeActions,
73
+ drawerActions: drawerActions
37
74
  )
38
75
  )
39
76
 
@@ -145,6 +182,54 @@ final class RnErxesSdk: NSObject {
145
182
  return nil
146
183
  }
147
184
 
185
+ /// Parse `[{ id, title, systemIcon }]` from JS into `[ActionItem]`.
186
+ /// Entries without an `id` are skipped; `title`/`systemIcon` default to empty.
187
+ private static func actionItems(_ value: Any?) -> [ActionItem] {
188
+ guard let array = value as? [[String: Any]] else {
189
+ return []
190
+ }
191
+
192
+ return array.compactMap { item in
193
+ guard let id = string(item["id"]) else { return nil }
194
+ return ActionItem(
195
+ id: id,
196
+ title: string(item["title"]) ?? "",
197
+ systemIcon: string(item["systemIcon"]) ?? ""
198
+ )
199
+ }
200
+ }
201
+
202
+ /// Parse a `#RGB`/`#RRGGBB`/`#RRGGBBAA` hex string into a UIColor.
203
+ private static func hexColor(_ value: Any?) -> UIColor? {
204
+ guard var hex = string(value) else { return nil }
205
+ if hex.hasPrefix("#") { hex.removeFirst() }
206
+
207
+ // Expand shorthand #RGB to #RRGGBB.
208
+ if hex.count == 3 {
209
+ hex = hex.map { "\($0)\($0)" }.joined()
210
+ }
211
+
212
+ guard hex.count == 6 || hex.count == 8,
213
+ let intValue = UInt64(hex, radix: 16) else {
214
+ return nil
215
+ }
216
+
217
+ let hasAlpha = hex.count == 8
218
+ let r, g, b, a: CGFloat
219
+ if hasAlpha {
220
+ r = CGFloat((intValue >> 24) & 0xFF) / 255
221
+ g = CGFloat((intValue >> 16) & 0xFF) / 255
222
+ b = CGFloat((intValue >> 8) & 0xFF) / 255
223
+ a = CGFloat(intValue & 0xFF) / 255
224
+ } else {
225
+ r = CGFloat((intValue >> 16) & 0xFF) / 255
226
+ g = CGFloat((intValue >> 8) & 0xFF) / 255
227
+ b = CGFloat(intValue & 0xFF) / 255
228
+ a = 1
229
+ }
230
+ return UIColor(red: r, green: g, blue: b, alpha: a)
231
+ }
232
+
148
233
  private static func stringDictionary(_ value: Any?) -> [String: String] {
149
234
  guard let dictionary = value as? [String: Any] else {
150
235
  return [:]
@@ -5,6 +5,14 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.ErxesNativeIOS = void 0;
7
7
  var _reactNative = require("react-native");
8
+ /**
9
+ * A chat-mode action rendered in the header (`homeActions`) or drawer
10
+ * (`drawerActions`). Kept data-only so it can cross the native bridge — tapping
11
+ * it fires the `onErxesAction` event with this `id` (see `addActionListener`).
12
+ */
13
+
14
+ /** Native event name emitted when a chat-mode action is tapped. */
15
+ const ACTION_EVENT = 'onErxesAction';
8
16
  const LINKING_ERROR = "The rn-erxes-sdk native iOS module is not linked. Run `pod install` in your app's ios directory and rebuild the app.";
9
17
  const nativeModule = _reactNative.NativeModules.RnErxesSdk;
10
18
  function getNativeModule() {
@@ -44,6 +52,16 @@ const ErxesNativeIOS = {
44
52
  },
45
53
  hideLauncher() {
46
54
  return getNativeModule().hideLauncher();
55
+ },
56
+ /**
57
+ * Listen for chat-mode action taps (`homeActions` / `drawerActions`). The
58
+ * handler receives the tapped action's `id`; your code decides what happens
59
+ * (navigate, open a modal, etc.). Returns a subscription — call `.remove()`
60
+ * to stop listening.
61
+ */
62
+ addActionListener(handler) {
63
+ const emitter = new _reactNative.NativeEventEmitter(getNativeModule());
64
+ return emitter.addListener(ACTION_EVENT, event => handler(event.id));
47
65
  }
48
66
  };
49
67
  exports.ErxesNativeIOS = ErxesNativeIOS;
@@ -1 +1 @@
1
- {"version":3,"names":["_reactNative","require","LINKING_ERROR","nativeModule","NativeModules","RnErxesSdk","getNativeModule","Platform","OS","Error","ErxesNativeIOS","configure","options","setUser","customData","Object","fromEntries","entries","filter","_ref","value","undefined","map","_ref2","key","String","clearUser","showMessenger","showLauncher","hideLauncher","exports"],"sourceRoot":"../../src","sources":["nativeIos.ts"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AA0BA,MAAMC,aAAa,GACjB,sHAAsH;AAExH,MAAMC,YAAY,GAAGC,0BAAa,CAACC,UAAyC;AAE5E,SAASC,eAAeA,CAAA,EAAoB;EAC1C,IAAIC,qBAAQ,CAACC,EAAE,KAAK,KAAK,EAAE;IACzB,MAAM,IAAIC,KAAK,CAAC,kDAAkD,CAAC;EACrE;EAEA,IAAI,CAACN,YAAY,EAAE;IACjB,MAAM,IAAIM,KAAK,CAACP,aAAa,CAAC;EAChC;EAEA,OAAOC,YAAY;AACrB;AAEO,MAAMO,cAAc,GAAG;EAC5BC,SAASA,CAACC,OAAwB,EAAE;IAClC,OAAON,eAAe,CAAC,CAAC,CAACK,SAAS,CAACC,OAAO,CAAC;EAC7C,CAAC;EACDC,OAAOA,CAACD,OAAsB,EAAE;IAC9B,MAAME,UAAU,GAAGC,MAAM,CAACC,WAAW,CACnCD,MAAM,CAACE,OAAO,CAACL,OAAO,CAACE,UAAU,IAAI,CAAC,CAAC,CAAC,CACrCI,MAAM,CAACC,IAAA;MAAA,IAAC,GAAGC,KAAK,CAAC,GAAAD,IAAA;MAAA,OAAKC,KAAK,KAAK,IAAI,IAAIA,KAAK,KAAKC,SAAS;IAAA,EAAC,CAC5DC,GAAG,CAACC,KAAA;MAAA,IAAC,CAACC,GAAG,EAAEJ,KAAK,CAAC,GAAAG,KAAA;MAAA,OAAK,CAACC,GAAG,EAAEC,MAAM,CAACL,KAAK,CAAC,CAAC;IAAA,EAC/C,CAAC;IAED,OAAOd,eAAe,CAAC,CAAC,CAACO,OAAO,CAAC;MAC/B,GAAGD,OAAO;MACVE;IACF,CAAC,CAAC;EACJ,CAAC;EACDY,SAASA,CAAA,EAAG;IACV,OAAOpB,eAAe,CAAC,CAAC,CAACoB,SAAS,CAAC,CAAC;EACtC,CAAC;EACDC,aAAaA,CAAA,EAAG;IACd,OAAOrB,eAAe,CAAC,CAAC,CAACqB,aAAa,CAAC,CAAC;EAC1C,CAAC;EACDC,YAAYA,CAAA,EAAG;IACb,OAAOtB,eAAe,CAAC,CAAC,CAACsB,YAAY,CAAC,CAAC;EACzC,CAAC;EACDC,YAAYA,CAAA,EAAG;IACb,OAAOvB,eAAe,CAAC,CAAC,CAACuB,YAAY,CAAC,CAAC;EACzC;AACF,CAAC;AAACC,OAAA,CAAApB,cAAA,GAAAA,cAAA"}
1
+ {"version":3,"names":["_reactNative","require","ACTION_EVENT","LINKING_ERROR","nativeModule","NativeModules","RnErxesSdk","getNativeModule","Platform","OS","Error","ErxesNativeIOS","configure","options","setUser","customData","Object","fromEntries","entries","filter","_ref","value","undefined","map","_ref2","key","String","clearUser","showMessenger","showLauncher","hideLauncher","addActionListener","handler","emitter","NativeEventEmitter","addListener","event","id","exports"],"sourceRoot":"../../src","sources":["nativeIos.ts"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAQA;AACA;AACA;AACA;AACA;;AA0CA;AACA,MAAMC,YAAY,GAAG,eAAe;AAEpC,MAAMC,aAAa,GACjB,sHAAsH;AAExH,MAAMC,YAAY,GAAGC,0BAAa,CAACC,UAAyC;AAE5E,SAASC,eAAeA,CAAA,EAAoB;EAC1C,IAAIC,qBAAQ,CAACC,EAAE,KAAK,KAAK,EAAE;IACzB,MAAM,IAAIC,KAAK,CAAC,kDAAkD,CAAC;EACrE;EAEA,IAAI,CAACN,YAAY,EAAE;IACjB,MAAM,IAAIM,KAAK,CAACP,aAAa,CAAC;EAChC;EAEA,OAAOC,YAAY;AACrB;AAEO,MAAMO,cAAc,GAAG;EAC5BC,SAASA,CAACC,OAAwB,EAAE;IAClC,OAAON,eAAe,CAAC,CAAC,CAACK,SAAS,CAACC,OAAO,CAAC;EAC7C,CAAC;EACDC,OAAOA,CAACD,OAAsB,EAAE;IAC9B,MAAME,UAAU,GAAGC,MAAM,CAACC,WAAW,CACnCD,MAAM,CAACE,OAAO,CAACL,OAAO,CAACE,UAAU,IAAI,CAAC,CAAC,CAAC,CACrCI,MAAM,CAACC,IAAA;MAAA,IAAC,GAAGC,KAAK,CAAC,GAAAD,IAAA;MAAA,OAAKC,KAAK,KAAK,IAAI,IAAIA,KAAK,KAAKC,SAAS;IAAA,EAAC,CAC5DC,GAAG,CAACC,KAAA;MAAA,IAAC,CAACC,GAAG,EAAEJ,KAAK,CAAC,GAAAG,KAAA;MAAA,OAAK,CAACC,GAAG,EAAEC,MAAM,CAACL,KAAK,CAAC,CAAC;IAAA,EAC/C,CAAC;IAED,OAAOd,eAAe,CAAC,CAAC,CAACO,OAAO,CAAC;MAC/B,GAAGD,OAAO;MACVE;IACF,CAAC,CAAC;EACJ,CAAC;EACDY,SAASA,CAAA,EAAG;IACV,OAAOpB,eAAe,CAAC,CAAC,CAACoB,SAAS,CAAC,CAAC;EACtC,CAAC;EACDC,aAAaA,CAAA,EAAG;IACd,OAAOrB,eAAe,CAAC,CAAC,CAACqB,aAAa,CAAC,CAAC;EAC1C,CAAC;EACDC,YAAYA,CAAA,EAAG;IACb,OAAOtB,eAAe,CAAC,CAAC,CAACsB,YAAY,CAAC,CAAC;EACzC,CAAC;EACDC,YAAYA,CAAA,EAAG;IACb,OAAOvB,eAAe,CAAC,CAAC,CAACuB,YAAY,CAAC,CAAC;EACzC,CAAC;EACD;AACF;AACA;AACA;AACA;AACA;EACEC,iBAAiBA,CAACC,OAA6B,EAAuB;IACpE,MAAMC,OAAO,GAAG,IAAIC,+BAAkB,CACpC3B,eAAe,CAAC,CAClB,CAAC;IACD,OAAO0B,OAAO,CAACE,WAAW,CAACjC,YAAY,EAAGkC,KAAqB,IAC7DJ,OAAO,CAACI,KAAK,CAACC,EAAE,CAClB,CAAC;EACH;AACF,CAAC;AAACC,OAAA,CAAA3B,cAAA,GAAAA,cAAA"}
@@ -1,4 +1,13 @@
1
- import { NativeModules, Platform } from 'react-native';
1
+ import { NativeEventEmitter, NativeModules, Platform } from 'react-native';
2
+
3
+ /**
4
+ * A chat-mode action rendered in the header (`homeActions`) or drawer
5
+ * (`drawerActions`). Kept data-only so it can cross the native bridge — tapping
6
+ * it fires the `onErxesAction` event with this `id` (see `addActionListener`).
7
+ */
8
+
9
+ /** Native event name emitted when a chat-mode action is tapped. */
10
+ const ACTION_EVENT = 'onErxesAction';
2
11
  const LINKING_ERROR = "The rn-erxes-sdk native iOS module is not linked. Run `pod install` in your app's ios directory and rebuild the app.";
3
12
  const nativeModule = NativeModules.RnErxesSdk;
4
13
  function getNativeModule() {
@@ -38,6 +47,16 @@ export const ErxesNativeIOS = {
38
47
  },
39
48
  hideLauncher() {
40
49
  return getNativeModule().hideLauncher();
50
+ },
51
+ /**
52
+ * Listen for chat-mode action taps (`homeActions` / `drawerActions`). The
53
+ * handler receives the tapped action's `id`; your code decides what happens
54
+ * (navigate, open a modal, etc.). Returns a subscription — call `.remove()`
55
+ * to stop listening.
56
+ */
57
+ addActionListener(handler) {
58
+ const emitter = new NativeEventEmitter(getNativeModule());
59
+ return emitter.addListener(ACTION_EVENT, event => handler(event.id));
41
60
  }
42
61
  };
43
62
  //# sourceMappingURL=nativeIos.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["NativeModules","Platform","LINKING_ERROR","nativeModule","RnErxesSdk","getNativeModule","OS","Error","ErxesNativeIOS","configure","options","setUser","customData","Object","fromEntries","entries","filter","_ref","value","undefined","map","_ref2","key","String","clearUser","showMessenger","showLauncher","hideLauncher"],"sourceRoot":"../../src","sources":["nativeIos.ts"],"mappings":"AAAA,SAASA,aAAa,EAAEC,QAAQ,QAAQ,cAAc;AA0BtD,MAAMC,aAAa,GACjB,sHAAsH;AAExH,MAAMC,YAAY,GAAGH,aAAa,CAACI,UAAyC;AAE5E,SAASC,eAAeA,CAAA,EAAoB;EAC1C,IAAIJ,QAAQ,CAACK,EAAE,KAAK,KAAK,EAAE;IACzB,MAAM,IAAIC,KAAK,CAAC,kDAAkD,CAAC;EACrE;EAEA,IAAI,CAACJ,YAAY,EAAE;IACjB,MAAM,IAAII,KAAK,CAACL,aAAa,CAAC;EAChC;EAEA,OAAOC,YAAY;AACrB;AAEA,OAAO,MAAMK,cAAc,GAAG;EAC5BC,SAASA,CAACC,OAAwB,EAAE;IAClC,OAAOL,eAAe,CAAC,CAAC,CAACI,SAAS,CAACC,OAAO,CAAC;EAC7C,CAAC;EACDC,OAAOA,CAACD,OAAsB,EAAE;IAC9B,MAAME,UAAU,GAAGC,MAAM,CAACC,WAAW,CACnCD,MAAM,CAACE,OAAO,CAACL,OAAO,CAACE,UAAU,IAAI,CAAC,CAAC,CAAC,CACrCI,MAAM,CAACC,IAAA;MAAA,IAAC,GAAGC,KAAK,CAAC,GAAAD,IAAA;MAAA,OAAKC,KAAK,KAAK,IAAI,IAAIA,KAAK,KAAKC,SAAS;IAAA,EAAC,CAC5DC,GAAG,CAACC,KAAA;MAAA,IAAC,CAACC,GAAG,EAAEJ,KAAK,CAAC,GAAAG,KAAA;MAAA,OAAK,CAACC,GAAG,EAAEC,MAAM,CAACL,KAAK,CAAC,CAAC;IAAA,EAC/C,CAAC;IAED,OAAOb,eAAe,CAAC,CAAC,CAACM,OAAO,CAAC;MAC/B,GAAGD,OAAO;MACVE;IACF,CAAC,CAAC;EACJ,CAAC;EACDY,SAASA,CAAA,EAAG;IACV,OAAOnB,eAAe,CAAC,CAAC,CAACmB,SAAS,CAAC,CAAC;EACtC,CAAC;EACDC,aAAaA,CAAA,EAAG;IACd,OAAOpB,eAAe,CAAC,CAAC,CAACoB,aAAa,CAAC,CAAC;EAC1C,CAAC;EACDC,YAAYA,CAAA,EAAG;IACb,OAAOrB,eAAe,CAAC,CAAC,CAACqB,YAAY,CAAC,CAAC;EACzC,CAAC;EACDC,YAAYA,CAAA,EAAG;IACb,OAAOtB,eAAe,CAAC,CAAC,CAACsB,YAAY,CAAC,CAAC;EACzC;AACF,CAAC"}
1
+ {"version":3,"names":["NativeEventEmitter","NativeModules","Platform","ACTION_EVENT","LINKING_ERROR","nativeModule","RnErxesSdk","getNativeModule","OS","Error","ErxesNativeIOS","configure","options","setUser","customData","Object","fromEntries","entries","filter","_ref","value","undefined","map","_ref2","key","String","clearUser","showMessenger","showLauncher","hideLauncher","addActionListener","handler","emitter","addListener","event","id"],"sourceRoot":"../../src","sources":["nativeIos.ts"],"mappings":"AAAA,SACEA,kBAAkB,EAClBC,aAAa,EACbC,QAAQ,QAGH,cAAc;;AAErB;AACA;AACA;AACA;AACA;;AA0CA;AACA,MAAMC,YAAY,GAAG,eAAe;AAEpC,MAAMC,aAAa,GACjB,sHAAsH;AAExH,MAAMC,YAAY,GAAGJ,aAAa,CAACK,UAAyC;AAE5E,SAASC,eAAeA,CAAA,EAAoB;EAC1C,IAAIL,QAAQ,CAACM,EAAE,KAAK,KAAK,EAAE;IACzB,MAAM,IAAIC,KAAK,CAAC,kDAAkD,CAAC;EACrE;EAEA,IAAI,CAACJ,YAAY,EAAE;IACjB,MAAM,IAAII,KAAK,CAACL,aAAa,CAAC;EAChC;EAEA,OAAOC,YAAY;AACrB;AAEA,OAAO,MAAMK,cAAc,GAAG;EAC5BC,SAASA,CAACC,OAAwB,EAAE;IAClC,OAAOL,eAAe,CAAC,CAAC,CAACI,SAAS,CAACC,OAAO,CAAC;EAC7C,CAAC;EACDC,OAAOA,CAACD,OAAsB,EAAE;IAC9B,MAAME,UAAU,GAAGC,MAAM,CAACC,WAAW,CACnCD,MAAM,CAACE,OAAO,CAACL,OAAO,CAACE,UAAU,IAAI,CAAC,CAAC,CAAC,CACrCI,MAAM,CAACC,IAAA;MAAA,IAAC,GAAGC,KAAK,CAAC,GAAAD,IAAA;MAAA,OAAKC,KAAK,KAAK,IAAI,IAAIA,KAAK,KAAKC,SAAS;IAAA,EAAC,CAC5DC,GAAG,CAACC,KAAA;MAAA,IAAC,CAACC,GAAG,EAAEJ,KAAK,CAAC,GAAAG,KAAA;MAAA,OAAK,CAACC,GAAG,EAAEC,MAAM,CAACL,KAAK,CAAC,CAAC;IAAA,EAC/C,CAAC;IAED,OAAOb,eAAe,CAAC,CAAC,CAACM,OAAO,CAAC;MAC/B,GAAGD,OAAO;MACVE;IACF,CAAC,CAAC;EACJ,CAAC;EACDY,SAASA,CAAA,EAAG;IACV,OAAOnB,eAAe,CAAC,CAAC,CAACmB,SAAS,CAAC,CAAC;EACtC,CAAC;EACDC,aAAaA,CAAA,EAAG;IACd,OAAOpB,eAAe,CAAC,CAAC,CAACoB,aAAa,CAAC,CAAC;EAC1C,CAAC;EACDC,YAAYA,CAAA,EAAG;IACb,OAAOrB,eAAe,CAAC,CAAC,CAACqB,YAAY,CAAC,CAAC;EACzC,CAAC;EACDC,YAAYA,CAAA,EAAG;IACb,OAAOtB,eAAe,CAAC,CAAC,CAACsB,YAAY,CAAC,CAAC;EACzC,CAAC;EACD;AACF;AACA;AACA;AACA;AACA;EACEC,iBAAiBA,CAACC,OAA6B,EAAuB;IACpE,MAAMC,OAAO,GAAG,IAAIhC,kBAAkB,CACpCO,eAAe,CAAC,CAClB,CAAC;IACD,OAAOyB,OAAO,CAACC,WAAW,CAAC9B,YAAY,EAAG+B,KAAqB,IAC7DH,OAAO,CAACG,KAAK,CAACC,EAAE,CAClB,CAAC;EACH;AACF,CAAC"}
@@ -1,3 +1,3 @@
1
1
  export { ErxesNativeIOS } from './nativeIos';
2
- export type { NativeIOSConfig, NativeIOSUser } from './nativeIos';
2
+ export type { NativeIOSAction, NativeIOSConfig, NativeIOSUser, } from './nativeIos';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EACV,eAAe,EACf,eAAe,EACf,aAAa,GACd,MAAM,aAAa,CAAC"}
@@ -1,9 +1,31 @@
1
+ import { type EmitterSubscription } from 'react-native';
2
+ /**
3
+ * A chat-mode action rendered in the header (`homeActions`) or drawer
4
+ * (`drawerActions`). Kept data-only so it can cross the native bridge — tapping
5
+ * it fires the `onErxesAction` event with this `id` (see `addActionListener`).
6
+ */
7
+ type NativeIOSAction = {
8
+ /** Identifier echoed back when the action is tapped. */
9
+ id: string;
10
+ /** Display title (drawer rows / accessibility label for header icons). */
11
+ title: string;
12
+ /** SF Symbol name, e.g. "magnifyingglass". */
13
+ systemIcon: string;
14
+ };
1
15
  type NativeIOSConfig = {
2
16
  integrationId: string;
3
17
  endpoint?: string;
4
18
  serverUrl?: string;
5
19
  subDomain?: string;
6
20
  cachedCustomerId?: string;
21
+ /** UI shell to present. Defaults to `'classic'` (the sheet-based widget). */
22
+ displayMode?: 'classic' | 'chat';
23
+ /** Chat-mode header-right actions. Ignored in `'classic'`. */
24
+ homeActions?: NativeIOSAction[];
25
+ /** Chat-mode drawer top action rows. Ignored in `'classic'`. */
26
+ drawerActions?: NativeIOSAction[];
27
+ /** Primary accent color as a hex string, e.g. `'#3f78d9'`. */
28
+ primaryColor?: string;
7
29
  };
8
30
  type NativeIOSUser = {
9
31
  email?: string;
@@ -18,6 +40,13 @@ export declare const ErxesNativeIOS: {
18
40
  showMessenger(): Promise<void>;
19
41
  showLauncher(): Promise<void>;
20
42
  hideLauncher(): Promise<void>;
43
+ /**
44
+ * Listen for chat-mode action taps (`homeActions` / `drawerActions`). The
45
+ * handler receives the tapped action's `id`; your code decides what happens
46
+ * (navigate, open a modal, etc.). Returns a subscription — call `.remove()`
47
+ * to stop listening.
48
+ */
49
+ addActionListener(handler: (id: string) => void): EmitterSubscription;
21
50
  };
22
- export type { NativeIOSConfig, NativeIOSUser };
51
+ export type { NativeIOSAction, NativeIOSConfig, NativeIOSUser };
23
52
  //# sourceMappingURL=nativeIos.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"nativeIos.d.ts","sourceRoot":"","sources":["../../src/nativeIos.ts"],"names":[],"mappings":"AAEA,KAAK,eAAe,GAAG;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,KAAK,aAAa,GAAG;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;CAC3E,CAAC;AA4BF,eAAO,MAAM,cAAc;uBACN,eAAe;qBAGjB,aAAa;;;;;CAwB/B,CAAC;AAEF,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,CAAC"}
1
+ {"version":3,"file":"nativeIos.d.ts","sourceRoot":"","sources":["../../src/nativeIos.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,mBAAmB,EAEzB,MAAM,cAAc,CAAC;AAEtB;;;;GAIG;AACH,KAAK,eAAe,GAAG;IACrB,wDAAwD;IACxD,EAAE,EAAE,MAAM,CAAC;IACX,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6EAA6E;IAC7E,WAAW,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IACjC,8DAA8D;IAC9D,WAAW,CAAC,EAAE,eAAe,EAAE,CAAC;IAChC,gEAAgE;IAChE,aAAa,CAAC,EAAE,eAAe,EAAE,CAAC;IAClC,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,KAAK,aAAa,GAAG;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;CAC3E,CAAC;AA+BF,eAAO,MAAM,cAAc;uBACN,eAAe;qBAGjB,aAAa;;;;;IAwB9B;;;;;OAKG;oCAC6B,MAAM,KAAK,IAAI,GAAG,mBAAmB;CAQtE,CAAC;AAEF,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,aAAa,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rn-erxes-sdk",
3
- "version": "0.2.5",
3
+ "version": "0.3.2",
4
4
  "description": "react-native erxes sdk",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -53,7 +53,8 @@
53
53
  },
54
54
  "homepage": "https://github.com/erxes/rn-erxes-sdk#readme",
55
55
  "publishConfig": {
56
- "registry": "https://registry.npmjs.org/"
56
+ "registry": "https://registry.npmjs.org/",
57
+ "access": "public"
57
58
  },
58
59
  "devDependencies": {
59
60
  "@babel/core": "^7.26.0",
@@ -36,10 +36,10 @@ Pod::Spec.new do |s|
36
36
  spm_dependency(
37
37
  s,
38
38
  url: 'https://github.com/erxes/erxes-ios-sdk.git',
39
- requirement: { :kind => 'exactVersion', :version => '0.30.5' },
39
+ requirement: { :kind => 'exactVersion', :version => '0.30.7' },
40
40
  products: ['MessengerSDK']
41
41
  )
42
42
  else
43
- raise 'rn-erxes-sdk requires React Native 0.81+ CocoaPods SPM support to install MessengerSDK 0.0.1'
43
+ raise 'rn-erxes-sdk requires React Native 0.81+ CocoaPods SPM support to install MessengerSDK 0.30.7'
44
44
  end
45
45
  end
package/src/index.tsx CHANGED
@@ -1,2 +1,6 @@
1
1
  export { ErxesNativeIOS } from './nativeIos';
2
- export type { NativeIOSConfig, NativeIOSUser } from './nativeIos';
2
+ export type {
3
+ NativeIOSAction,
4
+ NativeIOSConfig,
5
+ NativeIOSUser,
6
+ } from './nativeIos';
package/src/nativeIos.ts CHANGED
@@ -1,4 +1,24 @@
1
- import { NativeModules, Platform } from 'react-native';
1
+ import {
2
+ NativeEventEmitter,
3
+ NativeModules,
4
+ Platform,
5
+ type EmitterSubscription,
6
+ type NativeModule,
7
+ } from 'react-native';
8
+
9
+ /**
10
+ * A chat-mode action rendered in the header (`homeActions`) or drawer
11
+ * (`drawerActions`). Kept data-only so it can cross the native bridge — tapping
12
+ * it fires the `onErxesAction` event with this `id` (see `addActionListener`).
13
+ */
14
+ type NativeIOSAction = {
15
+ /** Identifier echoed back when the action is tapped. */
16
+ id: string;
17
+ /** Display title (drawer rows / accessibility label for header icons). */
18
+ title: string;
19
+ /** SF Symbol name, e.g. "magnifyingglass". */
20
+ systemIcon: string;
21
+ };
2
22
 
3
23
  type NativeIOSConfig = {
4
24
  integrationId: string;
@@ -6,6 +26,14 @@ type NativeIOSConfig = {
6
26
  serverUrl?: string;
7
27
  subDomain?: string;
8
28
  cachedCustomerId?: string;
29
+ /** UI shell to present. Defaults to `'classic'` (the sheet-based widget). */
30
+ displayMode?: 'classic' | 'chat';
31
+ /** Chat-mode header-right actions. Ignored in `'classic'`. */
32
+ homeActions?: NativeIOSAction[];
33
+ /** Chat-mode drawer top action rows. Ignored in `'classic'`. */
34
+ drawerActions?: NativeIOSAction[];
35
+ /** Primary accent color as a hex string, e.g. `'#3f78d9'`. */
36
+ primaryColor?: string;
9
37
  };
10
38
 
11
39
  type NativeIOSUser = {
@@ -24,6 +52,9 @@ type NativeIOSModule = {
24
52
  hideLauncher(): Promise<void>;
25
53
  };
26
54
 
55
+ /** Native event name emitted when a chat-mode action is tapped. */
56
+ const ACTION_EVENT = 'onErxesAction';
57
+
27
58
  const LINKING_ERROR =
28
59
  "The rn-erxes-sdk native iOS module is not linked. Run `pod install` in your app's ios directory and rebuild the app.";
29
60
 
@@ -69,6 +100,20 @@ export const ErxesNativeIOS = {
69
100
  hideLauncher() {
70
101
  return getNativeModule().hideLauncher();
71
102
  },
103
+ /**
104
+ * Listen for chat-mode action taps (`homeActions` / `drawerActions`). The
105
+ * handler receives the tapped action's `id`; your code decides what happens
106
+ * (navigate, open a modal, etc.). Returns a subscription — call `.remove()`
107
+ * to stop listening.
108
+ */
109
+ addActionListener(handler: (id: string) => void): EmitterSubscription {
110
+ const emitter = new NativeEventEmitter(
111
+ getNativeModule() as unknown as NativeModule
112
+ );
113
+ return emitter.addListener(ACTION_EVENT, (event: { id: string }) =>
114
+ handler(event.id)
115
+ );
116
+ },
72
117
  };
73
118
 
74
- export type { NativeIOSConfig, NativeIOSUser };
119
+ export type { NativeIOSAction, NativeIOSConfig, NativeIOSUser };