infobip-mobile-messaging-react-native-plugin 13.8.1 → 13.10.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.
- package/android/build.gradle +1 -1
- package/android/src/main/java/org/infobip/reactlibrary/mobilemessaging/RNMMChatModule.java +43 -6
- package/android/src/main/java/org/infobip/reactlibrary/mobilemessaging/RNMMChatViewManager.java +25 -12
- package/android/src/main/java/org/infobip/reactlibrary/mobilemessaging/ReactChatView.java +116 -30
- package/infobip-mobile-messaging-react-native-plugin-13.9.0.tgz +0 -0
- package/infobip-mobile-messaging-react-native-plugin.podspec +1 -1
- package/infobip-mobile-messaging-react-native-plugin.tgz +0 -0
- package/ios/MobileMessagingPlugin/RNMMChat.swift +25 -0
- package/ios/MobileMessagingPlugin/RNMMChatBridge.m +1 -0
- package/ios/MobileMessagingPlugin/RNMobileMessaging.swift +2 -1
- package/ios/MobileMessagingPlugin/RNMobileMessagingUtils.swift +2 -1
- package/package.json +1 -1
- package/src/components/RNMMChatViewNativeComponent.js +86 -25
- package/src/index.d.ts +26 -0
- package/src/index.js +53 -2
- package/infobip-mobile-messaging-react-native-plugin-13.8.0.tgz +0 -0
package/android/build.gradle
CHANGED
|
@@ -28,6 +28,8 @@ import org.infobip.mobile.messaging.chat.view.styles.InAppChatInputViewStyle;
|
|
|
28
28
|
import org.infobip.mobile.messaging.chat.view.styles.InAppChatStyle;
|
|
29
29
|
import org.infobip.mobile.messaging.chat.view.styles.InAppChatTheme;
|
|
30
30
|
import org.infobip.mobile.messaging.chat.view.styles.InAppChatToolbarStyle;
|
|
31
|
+
import org.infobip.mobile.messaging.chat.core.InAppChatException;
|
|
32
|
+
import org.infobip.mobile.messaging.chat.view.InAppChatErrorsHandler;
|
|
31
33
|
import org.infobip.mobile.messaging.chat.core.widget.LivechatWidgetLanguage;
|
|
32
34
|
import org.infobip.mobile.messaging.mobileapi.MobileMessagingError;
|
|
33
35
|
import org.infobip.mobile.messaging.mobileapi.Result;
|
|
@@ -50,7 +52,9 @@ import java.net.URL;
|
|
|
50
52
|
|
|
51
53
|
public class RNMMChatModule extends ReactContextBaseJavaModule implements ActivityEventListener, LifecycleEventListener {
|
|
52
54
|
|
|
53
|
-
private static final String EVENT_INAPPCHAT_JWT_REQUESTED = "inAppChat.jwtRequested";
|
|
55
|
+
private static final String EVENT_INAPPCHAT_JWT_REQUESTED = "inAppChat.internal.jwtRequested";
|
|
56
|
+
private static final String EVENT_INAPPCHAT_EXCEPTION_RECEIVED = "inAppChat.internal.exceptionReceived";
|
|
57
|
+
|
|
54
58
|
private static ReactApplicationContext reactContext;
|
|
55
59
|
private final ChatJwtCallbackHolder chatJwtCallbackHolder = new ChatJwtCallbackHolder();
|
|
56
60
|
|
|
@@ -72,11 +76,6 @@ public class RNMMChatModule extends ReactContextBaseJavaModule implements Activi
|
|
|
72
76
|
InAppChat.getInstance(reactContext).inAppChatScreen().show();
|
|
73
77
|
}
|
|
74
78
|
|
|
75
|
-
@ReactMethod
|
|
76
|
-
public void showThreadsList() {
|
|
77
|
-
InAppChat.getInstance(reactContext).showThreadsList();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
79
|
@ReactMethod
|
|
81
80
|
public void getMessageCounter(final Callback successCallback) {
|
|
82
81
|
successCallback.invoke(InAppChat.getInstance(reactContext).getMessageCounter());
|
|
@@ -221,6 +220,44 @@ public class RNMMChatModule extends ReactContextBaseJavaModule implements Activi
|
|
|
221
220
|
}
|
|
222
221
|
}
|
|
223
222
|
|
|
223
|
+
@ReactMethod
|
|
224
|
+
public void setChatExceptionHandler(boolean isHandlerPresent) {
|
|
225
|
+
if (isHandlerPresent) {
|
|
226
|
+
InAppChat.getInstance(reactContext).inAppChatScreen().setErrorHandler(createErrorsHandler());
|
|
227
|
+
} else {
|
|
228
|
+
InAppChat.getInstance(reactContext).inAppChatScreen().setErrorHandler(null);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
private InAppChatErrorsHandler createErrorsHandler() {
|
|
233
|
+
return new InAppChatErrorsHandler() {
|
|
234
|
+
@Override
|
|
235
|
+
public void handlerError(@NonNull String error) {
|
|
236
|
+
// Deprecated method
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
@Override
|
|
240
|
+
public void handlerWidgetError(@NonNull String error) {
|
|
241
|
+
// Deprecated method
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
@Override
|
|
245
|
+
public void handlerNoInternetConnectionError(boolean hasConnection) {
|
|
246
|
+
// Deprecated method
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
@Override
|
|
250
|
+
public boolean handleError(@NonNull InAppChatException exception) {
|
|
251
|
+
if (reactContext != null) {
|
|
252
|
+
ReactNativeEvent.send(EVENT_INAPPCHAT_EXCEPTION_RECEIVED, reactContext, exception.toJSON());
|
|
253
|
+
} else {
|
|
254
|
+
Log.e(Utils.TAG, "React context is null, cannot propagate chat exception.");
|
|
255
|
+
}
|
|
256
|
+
return true;
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
224
261
|
@ReactMethod
|
|
225
262
|
public void setWidgetTheme(String widgetTheme) {
|
|
226
263
|
if (widgetTheme != null) {
|
package/android/src/main/java/org/infobip/reactlibrary/mobilemessaging/RNMMChatViewManager.java
CHANGED
|
@@ -15,6 +15,8 @@ import com.facebook.react.uimanager.annotations.ReactProp;
|
|
|
15
15
|
class RNMMChatViewManager extends ViewGroupManager<ReactChatView> {
|
|
16
16
|
public static final String COMMAND_ADD = "add";
|
|
17
17
|
public static final String COMMAND_REMOVE = "remove";
|
|
18
|
+
public static final String COMMAND_SHOW_THREADS_LIST = "showThreadsList";
|
|
19
|
+
public static final String COMMAND_SET_EXCEPTION_HANDLER = "setExceptionHandler";
|
|
18
20
|
|
|
19
21
|
public static final String VIEW_GROUP_MANAGER_NAME = "RNMMChatView";
|
|
20
22
|
private ReactApplicationContext context;
|
|
@@ -42,20 +44,19 @@ class RNMMChatViewManager extends ViewGroupManager<ReactChatView> {
|
|
|
42
44
|
@Override
|
|
43
45
|
public void receiveCommand(@NonNull ReactChatView root, String commandId, @Nullable ReadableArray args) {
|
|
44
46
|
super.receiveCommand(root, commandId, args);
|
|
45
|
-
|
|
46
|
-
if (args == null) {
|
|
47
|
-
Log.e(Utils.TAG, "RNMMChatViewManager received command without argumnents, Id: " + commandId);
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
int reactNativeViewId = args.getInt(0);
|
|
51
|
-
|
|
52
47
|
switch (commandId) {
|
|
53
48
|
case COMMAND_ADD:
|
|
54
|
-
addChatFragment(root
|
|
49
|
+
addChatFragment(root);
|
|
55
50
|
break;
|
|
56
51
|
case COMMAND_REMOVE:
|
|
57
52
|
removeChatFragment(root);
|
|
58
53
|
break;
|
|
54
|
+
case COMMAND_SHOW_THREADS_LIST:
|
|
55
|
+
showThreadsList(root);
|
|
56
|
+
break;
|
|
57
|
+
case COMMAND_SET_EXCEPTION_HANDLER:
|
|
58
|
+
setExceptionHandler(root, args.getBoolean(0));
|
|
59
|
+
break;
|
|
59
60
|
default: {
|
|
60
61
|
Log.w(Utils.TAG, "RNMMChatViewManager received unsupported command with Id: " + commandId);
|
|
61
62
|
}
|
|
@@ -72,15 +73,27 @@ class RNMMChatViewManager extends ViewGroupManager<ReactChatView> {
|
|
|
72
73
|
view.setSendButtonColor(hexSendButtonColor, Utils.getFragmentActivity(this.context));
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
private void addChatFragment(
|
|
76
|
+
private void addChatFragment(ReactChatView chatView) {
|
|
77
|
+
if (chatView != null) {
|
|
78
|
+
chatView.addChatFragment(this.context, Utils.getFragmentActivity(this.context));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private void removeChatFragment(ReactChatView chatView) {
|
|
83
|
+
if (chatView != null) {
|
|
84
|
+
chatView.removeChatFragment(Utils.getFragmentActivity(this.context));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private void showThreadsList(ReactChatView chatView) {
|
|
76
89
|
if (chatView != null) {
|
|
77
|
-
chatView.
|
|
90
|
+
chatView.showThreadsList(Utils.getFragmentActivity(this.context));
|
|
78
91
|
}
|
|
79
92
|
}
|
|
80
93
|
|
|
81
|
-
private void
|
|
94
|
+
private void setExceptionHandler(ReactChatView chatView, boolean isHandlerPresent) {
|
|
82
95
|
if (chatView != null) {
|
|
83
|
-
chatView.
|
|
96
|
+
chatView.setExceptionHandler(isHandlerPresent, this.context, Utils.getFragmentActivity(this.context));
|
|
84
97
|
}
|
|
85
98
|
}
|
|
86
99
|
}
|
|
@@ -5,21 +5,32 @@ import android.os.Build;
|
|
|
5
5
|
import android.util.AttributeSet;
|
|
6
6
|
import android.util.Log;
|
|
7
7
|
import android.view.ViewGroup;
|
|
8
|
+
import android.view.ViewParent;
|
|
8
9
|
import android.widget.FrameLayout;
|
|
10
|
+
import android.view.ViewTreeObserver;
|
|
9
11
|
|
|
10
12
|
import androidx.annotation.NonNull;
|
|
11
13
|
import androidx.annotation.Nullable;
|
|
12
14
|
import androidx.annotation.RequiresApi;
|
|
13
15
|
import androidx.fragment.app.Fragment;
|
|
16
|
+
import androidx.fragment.app.FragmentContainerView;
|
|
14
17
|
import androidx.fragment.app.FragmentActivity;
|
|
15
18
|
import androidx.fragment.app.FragmentManager;
|
|
16
19
|
import androidx.fragment.app.FragmentTransaction;
|
|
17
20
|
|
|
18
21
|
import org.infobip.mobile.messaging.chat.InAppChat;
|
|
19
22
|
import org.infobip.mobile.messaging.chat.view.InAppChatFragment;
|
|
23
|
+
import org.infobip.mobile.messaging.chat.core.InAppChatException;
|
|
24
|
+
import org.infobip.mobile.messaging.chat.view.InAppChatErrorsHandler;
|
|
25
|
+
|
|
26
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
20
27
|
|
|
21
28
|
class ReactChatView extends FrameLayout {
|
|
22
29
|
|
|
30
|
+
private InAppChatFragment fragment;
|
|
31
|
+
private boolean useCustomErrorHandler = false;
|
|
32
|
+
private static final String EVENT_INAPPCHAT_EXCEPTION_RECEIVED = "inAppChat.internal.exceptionReceived";
|
|
33
|
+
|
|
23
34
|
public ReactChatView(@NonNull Context context) {
|
|
24
35
|
super(context);
|
|
25
36
|
}
|
|
@@ -37,56 +48,131 @@ class ReactChatView extends FrameLayout {
|
|
|
37
48
|
super(context, attrs, defStyleAttr, defStyleRes);
|
|
38
49
|
}
|
|
39
50
|
|
|
40
|
-
@Override
|
|
41
|
-
public void requestLayout() {
|
|
42
|
-
super.requestLayout();
|
|
43
|
-
|
|
44
|
-
//RN issue https://github.com/facebook/react-native/issues/17968
|
|
45
|
-
//Without this layout will not be called and view will not be displayed, because RN doesn't dispatches events to android views properly
|
|
46
|
-
post(measureAndLayout);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
51
|
public void setSendButtonColor(String hexColorString, @Nullable FragmentActivity fragmentActivity) {
|
|
50
52
|
Log.d(Utils.TAG, "Not implemented for Android, use IB_AppTheme.Chat theme instead");
|
|
51
53
|
}
|
|
52
54
|
|
|
53
|
-
|
|
54
|
-
if (
|
|
55
|
-
return;
|
|
55
|
+
private InAppChatFragment getFragment(FragmentActivity fragmentActivity) {
|
|
56
|
+
if (this.fragment != null) {
|
|
57
|
+
return this.fragment;
|
|
58
|
+
}
|
|
59
|
+
if (fragmentActivity != null) {
|
|
60
|
+
FragmentManager fragmentManager = fragmentActivity.getSupportFragmentManager();
|
|
61
|
+
if (fragmentManager != null) {
|
|
62
|
+
Fragment fragment = fragmentManager.findFragmentByTag(Utils.RN_IN_APP_CHAT_FRAGMENT_TAG);
|
|
63
|
+
if (fragment instanceof InAppChatFragment) {
|
|
64
|
+
return (InAppChatFragment) fragment;
|
|
65
|
+
}
|
|
66
|
+
} else {
|
|
67
|
+
Log.e(Utils.TAG, "FragmentManager is null, cannot get InAppChatFragment.");
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
Log.e(Utils.TAG, "FragmentActivity is null, cannot get InAppChatFragment.");
|
|
56
71
|
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
57
74
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
75
|
+
public void addChatFragment(@Nullable ReactApplicationContext reactContext, @Nullable FragmentActivity fragmentActivity) {
|
|
76
|
+
fragment = getFragment(fragmentActivity);
|
|
77
|
+
if (fragment == null) {
|
|
78
|
+
fragment = new InAppChatFragment();
|
|
79
|
+
}
|
|
80
|
+
fragment.setWithToolbar(false);
|
|
81
|
+
fragment.setWithInput(true);
|
|
82
|
+
if (useCustomErrorHandler && reactContext != null) {
|
|
83
|
+
fragment.setErrorsHandler(createErrorsHandler(reactContext));
|
|
84
|
+
}
|
|
62
85
|
|
|
86
|
+
ViewParent parent = this.getParent();
|
|
87
|
+
if (parent instanceof ViewGroup) {
|
|
88
|
+
setupLayoutHack((ViewGroup) parent);
|
|
89
|
+
} else {
|
|
90
|
+
Log.e(Utils.TAG, "Parent is not ViewGroup, cannot show InAppChatFragment.");
|
|
91
|
+
}
|
|
63
92
|
FragmentManager fragmentManager = fragmentActivity.getSupportFragmentManager();
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
(
|
|
93
|
+
if (fragmentManager != null) {
|
|
94
|
+
fragmentManager.beginTransaction()
|
|
95
|
+
.replace(this.getId(), fragment, Utils.RN_IN_APP_CHAT_FRAGMENT_TAG)
|
|
96
|
+
.commitNow();
|
|
97
|
+
} else {
|
|
98
|
+
Log.e(Utils.TAG, "FragmentManager is null, cannot add InAppChatFragment.");
|
|
70
99
|
}
|
|
71
100
|
}
|
|
72
101
|
|
|
73
|
-
public void removeChatFragment(
|
|
74
|
-
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
102
|
+
public void removeChatFragment(@Nullable FragmentActivity fragmentActivity) {
|
|
103
|
+
useCustomErrorHandler = false;
|
|
77
104
|
FragmentManager fragmentManager = fragmentActivity.getSupportFragmentManager();
|
|
78
|
-
|
|
79
|
-
|
|
105
|
+
Fragment fragment = getFragment(fragmentActivity);
|
|
106
|
+
if (fragment != null && fragmentManager != null) {
|
|
107
|
+
fragmentManager.beginTransaction()
|
|
108
|
+
.remove(fragment)
|
|
109
|
+
.commitNow();
|
|
110
|
+
} else {
|
|
111
|
+
Log.e(Utils.TAG, "InAppChatFragment or FragmentManager is null, cannot remove InAppChatFragment.");
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public void showThreadsList(@Nullable FragmentActivity fragmentActivity) {
|
|
116
|
+
InAppChatFragment fragment = getFragment(fragmentActivity);
|
|
80
117
|
if (fragment != null) {
|
|
81
|
-
|
|
118
|
+
fragment.showThreadList();
|
|
119
|
+
} else {
|
|
120
|
+
Log.e(Utils.TAG, "InAppChatFragment is null, cannot show threads list.");
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
public void setExceptionHandler(boolean isHandlerPresent, @Nullable ReactApplicationContext reactContext, @Nullable FragmentActivity fragmentActivity) {
|
|
125
|
+
//If exception handler is set before adding the fragment, it will be applied in addChatFragment()
|
|
126
|
+
useCustomErrorHandler = isHandlerPresent;
|
|
127
|
+
InAppChatFragment fragment = getFragment(fragmentActivity);
|
|
128
|
+
if (fragment != null && reactContext != null) {
|
|
129
|
+
if (isHandlerPresent) {
|
|
130
|
+
fragment.setErrorsHandler(createErrorsHandler(reactContext));
|
|
131
|
+
} else {
|
|
132
|
+
fragment.setErrorsHandler(fragment.getDefaultErrorsHandler());
|
|
133
|
+
}
|
|
82
134
|
}
|
|
83
|
-
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
private InAppChatFragment.ErrorsHandler createErrorsHandler(ReactApplicationContext reactContext) {
|
|
138
|
+
return new InAppChatFragment.ErrorsHandler() {
|
|
139
|
+
@Override
|
|
140
|
+
public void handlerError(@NonNull String error) {
|
|
141
|
+
// Deprecated method
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
@Override
|
|
145
|
+
public void handlerWidgetError(@NonNull String error) {
|
|
146
|
+
// Deprecated method
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
@Override
|
|
150
|
+
public void handlerNoInternetConnectionError(boolean hasConnection) {
|
|
151
|
+
// Deprecated method
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
@Override
|
|
155
|
+
public boolean handleError(@NonNull InAppChatException exception) {
|
|
156
|
+
ReactNativeEvent.send(EVENT_INAPPCHAT_EXCEPTION_RECEIVED, reactContext, exception.toJSON());
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
};
|
|
84
160
|
}
|
|
85
161
|
|
|
86
162
|
private void setupLayoutHack(final ViewGroup view) {
|
|
87
163
|
view.getViewTreeObserver().addOnGlobalLayoutListener(view::requestLayout);
|
|
88
164
|
}
|
|
89
165
|
|
|
166
|
+
@Override
|
|
167
|
+
public void requestLayout() {
|
|
168
|
+
super.requestLayout();
|
|
169
|
+
|
|
170
|
+
// RN issue https://github.com/facebook/react-native/issues/17968
|
|
171
|
+
// Without this layout will not be called and view will not be displayed,
|
|
172
|
+
// because RN doesn't dispatches events to android views properly
|
|
173
|
+
post(measureAndLayout);
|
|
174
|
+
}
|
|
175
|
+
|
|
90
176
|
private final Runnable measureAndLayout = () -> {
|
|
91
177
|
measure(
|
|
92
178
|
MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY),
|
|
Binary file
|
|
Binary file
|
|
@@ -11,6 +11,7 @@ import MobileMessaging
|
|
|
11
11
|
@objc(RNMMChat)
|
|
12
12
|
class RNMMChat: NSObject {
|
|
13
13
|
private var willUseJWT = false
|
|
14
|
+
private var willUseChatExceptionHandler = false
|
|
14
15
|
private var jwtRequestQueue: [((String?) -> Void)] = []
|
|
15
16
|
private let jwtQueueLock = NSLock()
|
|
16
17
|
|
|
@@ -143,6 +144,12 @@ class RNMMChat: NSObject {
|
|
|
143
144
|
willUseJWT = true
|
|
144
145
|
}
|
|
145
146
|
|
|
147
|
+
@objc(setChatExceptionHandler:)
|
|
148
|
+
func setChatExceptionHandler(isHandlerPresent: NSNumber) {
|
|
149
|
+
// NSNumber due to how RN bridge wraps JavaScript booleans
|
|
150
|
+
willUseChatExceptionHandler = isHandlerPresent.boolValue
|
|
151
|
+
}
|
|
152
|
+
|
|
146
153
|
@objc(setChatJwt:)
|
|
147
154
|
func setChatJwt(jwt: String?) {
|
|
148
155
|
jwtQueueLock.lock()
|
|
@@ -181,4 +188,22 @@ extension RNMMChat: MMInAppChatDelegate {
|
|
|
181
188
|
_ = semaphore.wait(timeout: .now() + 45)
|
|
182
189
|
return jwtResult
|
|
183
190
|
}
|
|
191
|
+
|
|
192
|
+
@objc public func didReceiveException(_ exception: MMChatException) -> MMChatExceptionDisplayMode {
|
|
193
|
+
guard willUseChatExceptionHandler else { return .displayDefaultAlert }
|
|
194
|
+
|
|
195
|
+
var payload: [String: Any] = [:]
|
|
196
|
+
if let message = exception.message {
|
|
197
|
+
payload["message"] = message
|
|
198
|
+
}
|
|
199
|
+
if let name = exception.name {
|
|
200
|
+
payload["name"] = name
|
|
201
|
+
}
|
|
202
|
+
payload["code"] = exception.code
|
|
203
|
+
payload["origin"] = "LiveChat"
|
|
204
|
+
payload["platform"] = "Flutter"
|
|
205
|
+
|
|
206
|
+
ReactNativeMobileMessaging.shared?.sendEvent(withName: EventName.inAppChat_exceptionReceived, body: payload)
|
|
207
|
+
return .noDisplay
|
|
208
|
+
}
|
|
184
209
|
}
|
|
@@ -23,6 +23,7 @@ RCT_EXTERN_METHOD(setChatCustomization:)
|
|
|
23
23
|
RCT_EXTERN_METHOD(setLanguage:(NSString *)data onSuccess:(RCTResponseSenderBlock)successCallback onError:(RCTResponseSenderBlock)errorCallback)
|
|
24
24
|
RCT_EXTERN_METHOD(setChatJwt:)
|
|
25
25
|
RCT_EXTERN_METHOD(setChatJwtProvider)
|
|
26
|
+
RCT_EXTERN_METHOD(setChatExceptionHandler:)
|
|
26
27
|
RCT_EXTERN_METHOD(sendContextualData:(NSString *)data chatMultiThreadStrategy:(NSString *)chatMultiThreadStrategy onSuccess:(RCTResponseSenderBlock)successCallback onError:(RCTResponseSenderBlock)errorCallback)
|
|
27
28
|
RCT_EXTERN_METHOD(showThreadsList)
|
|
28
29
|
RCT_EXTERN_METHOD(restartConnection)
|
|
@@ -41,7 +41,8 @@ class ReactNativeMobileMessaging: RCTEventEmitter {
|
|
|
41
41
|
EventName.inAppChat_viewStateChanged,
|
|
42
42
|
EventName.inAppChat_configurationSynced,
|
|
43
43
|
EventName.inAppChat_registrationIdUpdated,
|
|
44
|
-
EventName.inAppChat_jwtRequested
|
|
44
|
+
EventName.inAppChat_jwtRequested,
|
|
45
|
+
EventName.inAppChat_exceptionReceived
|
|
45
46
|
]
|
|
46
47
|
}
|
|
47
48
|
|
|
@@ -107,7 +107,8 @@ struct EventName {
|
|
|
107
107
|
static let inAppChat_viewStateChanged = "inAppChat.viewStateChanged"
|
|
108
108
|
static let inAppChat_configurationSynced = "inAppChat.configurationSynced"
|
|
109
109
|
static let inAppChat_registrationIdUpdated = "inAppChat.livechatRegistrationIdUpdated"
|
|
110
|
-
static let inAppChat_jwtRequested = "inAppChat.jwtRequested"
|
|
110
|
+
static let inAppChat_jwtRequested = "inAppChat.internal.jwtRequested"
|
|
111
|
+
static let inAppChat_exceptionReceived = "inAppChat.internal.exceptionReceived"
|
|
111
112
|
}
|
|
112
113
|
|
|
113
114
|
extension UIApplication {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "infobip-mobile-messaging-react-native-plugin",
|
|
3
3
|
"title": "Infobip Mobile Messaging React Native Plugin",
|
|
4
|
-
"version": "13.
|
|
4
|
+
"version": "13.10.0",
|
|
5
5
|
"description": "Infobip Mobile Messaging React Native Plugin",
|
|
6
6
|
"main": "./src/index.js",
|
|
7
7
|
"scripts": {
|
|
@@ -1,51 +1,112 @@
|
|
|
1
1
|
import PropTypes from 'prop-types';
|
|
2
|
-
import React, {
|
|
2
|
+
import React, { useLayoutEffect, useRef, useImperativeHandle, forwardRef } from "react";
|
|
3
3
|
import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
interface RNMMChatViewProps {
|
|
7
|
-
sendButtonColor: ?string
|
|
8
|
-
}
|
|
4
|
+
import { requireNativeComponent, Platform, NativeEventEmitter, NativeModules } from 'react-native'
|
|
5
|
+
import { mobileMessaging } from 'infobip-mobile-messaging-react-native-plugin';
|
|
9
6
|
|
|
10
7
|
const RNMMChatViewCommands = codegenNativeCommands({
|
|
11
|
-
supportedCommands: ["add", "remove"],
|
|
8
|
+
supportedCommands: ["add", "remove", "showThreadsList", "setExceptionHandler"],
|
|
12
9
|
});
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
|
|
12
|
+
export const ChatView = forwardRef((props, ref) => {
|
|
13
|
+
const CHAT_EVENT_EXCEPTION_RECEIVED = 'inAppChat.internal.exceptionReceived';
|
|
14
|
+
const innerRef = useRef(null);
|
|
15
|
+
let eventEmitter = new NativeEventEmitter(NativeModules.ReactNativeMobileMessaging);
|
|
16
|
+
|
|
17
|
+
useImperativeHandle(ref, () => ({
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Navigates to THREAD_LIST view in multithread widget.
|
|
21
|
+
* @name showThreadsList
|
|
22
|
+
*/
|
|
23
|
+
showThreadsList: () => {
|
|
24
|
+
if (Platform.OS === "ios") {
|
|
25
|
+
mobileMessaging.showThreadsList();
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
// Nothing to do if there is no chatView reference.
|
|
29
|
+
let chatViewRef = innerRef.current;
|
|
30
|
+
if (!chatViewRef) return;
|
|
31
|
+
RNMMChatViewCommands.showThreadsList(chatViewRef);
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Sets the chat exception handler in case you want to intercept and
|
|
36
|
+
* display the errors coming from the chat on your own (instead of relying on the prebuild error banners).
|
|
37
|
+
*
|
|
38
|
+
* The `exceptionHandler` is a function that receives the exception. Passing `null` will remove the previously set handler.
|
|
39
|
+
*
|
|
40
|
+
* ```ts
|
|
41
|
+
* chatViewRef.current?.setChatExceptionHandler((exception) => {
|
|
42
|
+
* console.log("ChatView exception occurred:", exception);
|
|
43
|
+
* });
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* @param exceptionHandler A function that receives an ChatException when it happens. Passing `null` will remove the previously set handler.
|
|
47
|
+
* @param onError Optional error handler for catching exceptions thrown when listening for exceptions.
|
|
48
|
+
*/
|
|
49
|
+
setExceptionHandler(exceptionHandler, onError) {
|
|
50
|
+
// Not needed for iOS.
|
|
51
|
+
if (Platform.OS === "ios") {
|
|
52
|
+
mobileMessaging.setChatExceptionHandler(
|
|
53
|
+
(exception) => console.log('ChatView exception received: ' + JSON.stringify(exception)),
|
|
54
|
+
(error) => console.log('ChatView exception handler error: ' + error)
|
|
55
|
+
);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Nothing to do if there is no chatView reference.
|
|
60
|
+
let chatViewRef = innerRef.current;
|
|
61
|
+
if (!chatViewRef) return;
|
|
62
|
+
|
|
63
|
+
eventEmitter.removeAllListeners(CHAT_EVENT_EXCEPTION_RECEIVED);
|
|
64
|
+
let isHandlerPresent = typeof exceptionHandler === 'function';
|
|
65
|
+
if (isHandlerPresent) {
|
|
66
|
+
const handleError = (e) => {
|
|
67
|
+
if (onError) {
|
|
68
|
+
onError(e);
|
|
69
|
+
} else {
|
|
70
|
+
console.error('[RNMobileMessaging] Could not handle chat exception:', e);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
eventEmitter.addListener(CHAT_EVENT_EXCEPTION_RECEIVED, (chatException) => {
|
|
75
|
+
try {
|
|
76
|
+
exceptionHandler(chatException);
|
|
77
|
+
} catch (e) {
|
|
78
|
+
handleError(e);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
RNMMChatViewCommands.setExceptionHandler(chatViewRef, isHandlerPresent);
|
|
83
|
+
}
|
|
84
|
+
}));
|
|
16
85
|
|
|
17
86
|
useLayoutEffect(() => {
|
|
18
87
|
// Not needed for iOS.
|
|
19
88
|
if (Platform.OS === "ios") return;
|
|
20
89
|
|
|
21
|
-
const chatViewRef = ref.current
|
|
22
90
|
// Nothing to do if there is no chatView reference.
|
|
91
|
+
const chatViewRef = innerRef.current;
|
|
23
92
|
if (!chatViewRef) return;
|
|
24
93
|
|
|
25
|
-
let addedViewId: ?number = null
|
|
26
|
-
|
|
27
94
|
// Fix for android, sometimes it can't get parent view, which is needed
|
|
28
95
|
// for proper relayout.
|
|
29
96
|
setTimeout(() => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
RNMMChatViewCommands.add(chatViewRef, viewId);
|
|
33
|
-
console.log(`Adding android viewId: ${viewId}.`);
|
|
34
|
-
addedViewId = viewId;
|
|
35
|
-
}
|
|
97
|
+
console.log(`add command called`);
|
|
98
|
+
RNMMChatViewCommands.add(chatViewRef);
|
|
36
99
|
}, 100);
|
|
37
100
|
|
|
38
101
|
return () => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
RNMMChatViewCommands.remove(chatViewRef, viewId);
|
|
43
|
-
}
|
|
102
|
+
console.log(`remove command called`);
|
|
103
|
+
eventEmitter.removeAllListeners(CHAT_EVENT_EXCEPTION_RECEIVED);
|
|
104
|
+
RNMMChatViewCommands.remove(chatViewRef);
|
|
44
105
|
};
|
|
45
106
|
}, []);
|
|
46
107
|
|
|
47
|
-
return <RNMMChatView {...props} ref={
|
|
48
|
-
};
|
|
108
|
+
return <RNMMChatView {...props} ref={innerRef} />;
|
|
109
|
+
});
|
|
49
110
|
|
|
50
111
|
ChatView.propTypes = {
|
|
51
112
|
/**
|
package/src/index.d.ts
CHANGED
|
@@ -265,6 +265,14 @@ declare namespace MobileMessagingReactNative {
|
|
|
265
265
|
chatInputCursorColor: string;
|
|
266
266
|
}
|
|
267
267
|
|
|
268
|
+
export interface ChatException {
|
|
269
|
+
code?: number;
|
|
270
|
+
name?: string;
|
|
271
|
+
message?: string;
|
|
272
|
+
origin?: string;
|
|
273
|
+
platform?: string;
|
|
274
|
+
}
|
|
275
|
+
|
|
268
276
|
// To be deprecated in favour of ChatCustomization above
|
|
269
277
|
export interface ChatCustomizationConfiguration {
|
|
270
278
|
toolbarTitle: string;
|
|
@@ -635,6 +643,7 @@ declare namespace MobileMessagingReactNative {
|
|
|
635
643
|
resetMessageCounter(): void;
|
|
636
644
|
|
|
637
645
|
/**
|
|
646
|
+
* This method is iOS only and it has no effect in Android.
|
|
638
647
|
* Navigates to THREAD_LIST view in multithread widget if in-app chat is shown as React Component.
|
|
639
648
|
* @name showThreadsList
|
|
640
649
|
*/
|
|
@@ -670,6 +679,23 @@ declare namespace MobileMessagingReactNative {
|
|
|
670
679
|
*/
|
|
671
680
|
setChatJwtProvider(jwtProvider: () => string | Promise<string>, onError?: (error: Error) => void): void;
|
|
672
681
|
|
|
682
|
+
/**
|
|
683
|
+
* Sets the chat exception handler in case you want to intercept and
|
|
684
|
+
* display the errors coming from the chat on your own (instead of relying on the prebuild error banners).
|
|
685
|
+
*
|
|
686
|
+
* The `exceptionHandler` is a function that receives the exception. Passing `null` will remove the previously set handler.
|
|
687
|
+
*
|
|
688
|
+
* ```ts
|
|
689
|
+
* mobileMessaging.setChatExceptionHandler((exception) => {
|
|
690
|
+
* console.log("Chat exception occurred:", exception);
|
|
691
|
+
* });
|
|
692
|
+
* ```
|
|
693
|
+
*
|
|
694
|
+
* @param exceptionHandler A function that receives an ChatException when it happens. Passing `null` will remove the previously set handler.
|
|
695
|
+
* @param onError Optional error handler for catching exceptions thrown when listening for exceptions.
|
|
696
|
+
*/
|
|
697
|
+
setChatExceptionHandler(exceptionHandler?: (exception?: ChatException) => void, onError?: (error: Error) => void): void;
|
|
698
|
+
|
|
673
699
|
/**
|
|
674
700
|
* Registering for POST_NOTIFICATIONS permission for Android 13+
|
|
675
701
|
*/
|
package/src/index.js
CHANGED
|
@@ -639,15 +639,19 @@ class MobileMessaging {
|
|
|
639
639
|
|
|
640
640
|
|
|
641
641
|
/**
|
|
642
|
+
* This method is iOS only and it has no effect in Android.
|
|
642
643
|
* Navigates to THREAD_LIST view in multithread widget if in-app chat is shown as React Component.
|
|
643
644
|
* @name showThreadsList
|
|
644
645
|
*/
|
|
645
646
|
showThreadsList() {
|
|
647
|
+
if (Platform.OS === "android") {
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
646
650
|
RNMMChat.showThreadsList();
|
|
647
651
|
};
|
|
648
652
|
|
|
649
653
|
/**
|
|
650
|
-
* Private global variable holding reference to
|
|
654
|
+
* Private global variable holding reference to jwt update events subscription.
|
|
651
655
|
*/
|
|
652
656
|
#jwtSubscription = null;
|
|
653
657
|
|
|
@@ -696,7 +700,7 @@ class MobileMessaging {
|
|
|
696
700
|
}
|
|
697
701
|
};
|
|
698
702
|
|
|
699
|
-
this.#jwtSubscription = this.subscribe('inAppChat.jwtRequested', () => {
|
|
703
|
+
this.#jwtSubscription = this.subscribe('inAppChat.internal.jwtRequested', () => {
|
|
700
704
|
try {
|
|
701
705
|
const jwtPromise = jwtProvider();
|
|
702
706
|
if (jwtPromise && typeof jwtPromise.then === 'function') { // Handle asynchronous JWT provider of type Promise<string>
|
|
@@ -713,6 +717,53 @@ class MobileMessaging {
|
|
|
713
717
|
}
|
|
714
718
|
}
|
|
715
719
|
|
|
720
|
+
/**
|
|
721
|
+
* Private global variable holding reference to chat exceptions subscription.
|
|
722
|
+
*/
|
|
723
|
+
#chatExceptionHandlerSubscription = null;
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* Sets the chat exception handler in case you want to intercept and
|
|
727
|
+
* display the errors coming from the chat on your own (instead of relying on the prebuild error banners).
|
|
728
|
+
*
|
|
729
|
+
* The `exceptionHandler` is a function that receives the exception. Passing `null` will remove the previously set handler.
|
|
730
|
+
*
|
|
731
|
+
* ```ts
|
|
732
|
+
* mobileMessaging.setChatExceptionHandler((exception) => {
|
|
733
|
+
* console.log("Chat exception occurred:", exception);
|
|
734
|
+
* });
|
|
735
|
+
* ```
|
|
736
|
+
*
|
|
737
|
+
* @param exceptionHandler A function that receives an ChatException when it happens. Passing `null` will remove the previously set handler.
|
|
738
|
+
* @param onError Optional error handler for catching exceptions thrown when listening for exceptions.
|
|
739
|
+
*/
|
|
740
|
+
setChatExceptionHandler(exceptionHandler, onError) {
|
|
741
|
+
if (this.#chatExceptionHandlerSubscription != null) {
|
|
742
|
+
this.unsubscribe(this.#chatExceptionHandlerSubscription);
|
|
743
|
+
this.#chatExceptionHandlerSubscription = null;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
let isHandlerPresent = typeof exceptionHandler === 'function';
|
|
747
|
+
if (isHandlerPresent) {
|
|
748
|
+
const handleError = (e) => {
|
|
749
|
+
if (onError) {
|
|
750
|
+
onError(e);
|
|
751
|
+
} else {
|
|
752
|
+
console.error('[RNMobileMessaging] Could not handle chat exception:', e);
|
|
753
|
+
}
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
this.#chatExceptionHandlerSubscription = this.subscribe('inAppChat.internal.exceptionReceived', (chatException) => {
|
|
757
|
+
try {
|
|
758
|
+
exceptionHandler(chatException);
|
|
759
|
+
} catch (e) {
|
|
760
|
+
handleError(e);
|
|
761
|
+
}
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
RNMMChat.setChatExceptionHandler(isHandlerPresent);
|
|
765
|
+
}
|
|
766
|
+
|
|
716
767
|
/**
|
|
717
768
|
* Registering for POST_NOTIFICATIONS permission for Android 13+
|
|
718
769
|
*/
|
|
Binary file
|