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 +56 -22
- package/docs/native-ios.md +99 -1
- package/ios/RnErxesSdk.m +2 -1
- package/ios/RnErxesSdk.swift +89 -4
- package/lib/commonjs/nativeIos.js +18 -0
- package/lib/commonjs/nativeIos.js.map +1 -1
- package/lib/module/nativeIos.js +20 -1
- package/lib/module/nativeIos.js.map +1 -1
- package/lib/typescript/index.d.ts +1 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/nativeIos.d.ts +30 -1
- package/lib/typescript/nativeIos.d.ts.map +1 -1
- package/package.json +3 -2
- package/rn-erxes-sdk.podspec +2 -2
- package/src/index.tsx +5 -1
- package/src/nativeIos.ts +47 -2
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
|
-
##
|
|
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
|
-
|
|
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.
|
|
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.
|
package/docs/native-ios.md
CHANGED
|
@@ -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.
|
|
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,
|
|
4
|
+
@interface RCT_EXTERN_MODULE(RnErxesSdk, RCTEventEmitter)
|
|
4
5
|
|
|
5
6
|
RCT_EXTERN_METHOD(configure:(NSDictionary *)options
|
|
6
7
|
resolver:(RCTPromiseResolveBlock)resolve
|
package/ios/RnErxesSdk.swift
CHANGED
|
@@ -4,12 +4,29 @@ import UIKit
|
|
|
4
4
|
import React
|
|
5
5
|
|
|
6
6
|
@objc(RnErxesSdk)
|
|
7
|
-
final class RnErxesSdk:
|
|
8
|
-
|
|
9
|
-
static
|
|
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;
|
|
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"}
|
package/lib/module/nativeIos.js
CHANGED
|
@@ -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,
|
|
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 +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,
|
|
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":"
|
|
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
|
|
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",
|
package/rn-erxes-sdk.podspec
CHANGED
|
@@ -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.
|
|
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.
|
|
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
package/src/nativeIos.ts
CHANGED
|
@@ -1,4 +1,24 @@
|
|
|
1
|
-
import {
|
|
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 };
|