diff --git a/README.md b/README.md
index f568faa..36bf00b 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
+
# helpshift-react-native
## Getting started
@@ -21,7 +22,7 @@
#### Android
1. Open up `android/app/src/main/java/[...]/MainActivity.java`
- - Add `import com.reactlibrary.RNHelpshiftPackage;` to the imports at the top of the file
+ - Add `import com.helpshift.reactlibrary.RNHelpshiftPackage;` to the imports at the top of the file
- Add `new RNHelpshiftPackage()` to the list returned by the `getPackages()` method
2. Append the following lines to `android/settings.gradle`:
```
@@ -84,6 +85,29 @@ render() {
}
```
+### IMPORTANT FOR USING COMPONENT ON ANDROID
+You must inherit style from Helpshift Themes to use the `` component in your app like so:
+
+```
+
+
+
+
+```
+
+The options for default themes are:
+
+- Helpshift.Theme.Light.DarkActionBar
+- Helpshift.Theme.Light
+- Helpshift.Theme.Dark
+- Helpshift.Theme.HighContrast
+- Helpshift.Theme.DayNight.DarkActionBar
+- Helpshift.Theme.DayNight.Light
+- Helpshift.Theme.DayNight.HighContrast
+
+If you would like to customize these themes please refer to Helpshift style guide [here](https://developers.helpshift.com/android/design/#skinning)
+
## API Usage
#### Initialize
```javascript
@@ -157,4 +181,3 @@ async _getUnreadMessagesCount(){
this.setState({ unreadMessages: count });
}
```
-
\ No newline at end of file
diff --git a/android/build.gradle b/android/build.gradle
index 2dba9d3..43e5ee4 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -12,7 +12,7 @@ buildscript {
apply plugin: 'com.android.library'
android {
- compileSdkVersion 28
+ compileSdkVersion 30
buildToolsVersion "28.0.3"
defaultConfig {
@@ -36,6 +36,6 @@ dependencies {
implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.android.support:cardview-v7:28.0.0'
- implementation 'com.helpshift:android-helpshift-aar:7.6.2'
+ implementation 'com.helpshift:android-helpshift-aar:7.9.0'
}
\ No newline at end of file
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
index 41a92ab..a8c510e 100644
--- a/android/src/main/AndroidManifest.xml
+++ b/android/src/main/AndroidManifest.xml
@@ -1,6 +1,6 @@
+ package="com.helpshift.reactlibrary">
\ No newline at end of file
diff --git a/android/src/main/java/com/reactlibrary/RNHelpshiftModule.java b/android/src/main/java/com/reactlibrary/RNHelpshiftModule.java
index 22cc48c..f4df1ab 100644
--- a/android/src/main/java/com/reactlibrary/RNHelpshiftModule.java
+++ b/android/src/main/java/com/reactlibrary/RNHelpshiftModule.java
@@ -1,157 +1,237 @@
-package com.reactlibrary;
+package com.helpshift.reactlibrary;
+
+import android.app.Activity;
+import android.app.Application;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
-import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
-
-import java.util.Map;
-import java.util.HashMap;
-
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.helpshift.Core;
-import com.helpshift.exceptions.InstallException;
-import com.helpshift.support.Support;
+import com.helpshift.CoreInternal;
import com.helpshift.HelpshiftUser;
+import com.helpshift.InstallConfig;
+import com.helpshift.delegate.AuthenticationFailureReason;
+import com.helpshift.exceptions.InstallException;
import com.helpshift.support.ApiConfig;
+import com.helpshift.support.Support;
-import android.app.Activity;
-import android.app.Application;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-
-import androidx.annotation.Nullable;
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
-public class RNHelpshiftModule extends ReactContextBaseJavaModule {
-
- private final Application app;
- private ReactApplicationContext mReactContext;
- private Handler countSuccessHandler;
- private Handler countErrorHandler;
-
- public RNHelpshiftModule(ReactApplicationContext reactContext) {
- super(reactContext);
-
- mReactContext= reactContext;
-
- this.app = (Application)reactContext.getApplicationContext();
- }
-
- @ReactMethod
- public void init(String key, String domain, String appid) throws InstallException {
- Core.init(Support.getInstance());
- Core.install(this.app, key, domain, appid);
- }
-
- @ReactMethod
- public void login(ReadableMap user){
- HelpshiftUser userBuilder;
- String email = user.hasKey("email") ? user.getString("email") : null;
- String indentifier = user.hasKey("indentifier") ? user.getString("indentifier") : null;
- if(user.hasKey("name") && user.hasKey("authToken")) {
- userBuilder = new HelpshiftUser.Builder(indentifier, email)
- .setName(user.getString("name"))
- .setAuthToken(user.getString("authToken"))
- .build();
- } else if (user.hasKey("name")) {
- userBuilder = new HelpshiftUser.Builder(indentifier, email)
- .setName(user.getString("name"))
- .build();
- } else if (user.hasKey("authToken")) {
- userBuilder = new HelpshiftUser.Builder(indentifier, email)
- .setAuthToken(user.getString("authToken"))
- .build();
- } else {
- userBuilder = new HelpshiftUser.Builder(indentifier, email).build();
- }
-
- Core.login(userBuilder);
- }
-
- @ReactMethod
- public void logout(){
- Core.logout();
- }
-
- @ReactMethod
- public void showConversation(){
- final Activity activity = getCurrentActivity();
- Support.showConversation(activity);
- }
-
- @ReactMethod
- public void showConversationWithCIFs(ReadableMap cifs){
- final Activity activity = getCurrentActivity();
- ApiConfig apiConfig = new ApiConfig.Builder().setCustomIssueFields(getCustomIssueFields(cifs)).build();
- Support.showConversation(activity, apiConfig);
- }
-
- @ReactMethod
- public void showFAQs(){
- final Activity activity = getCurrentActivity();
- Support.showFAQs(activity);
- }
-
- @ReactMethod
- public void showFAQsWithCIFs(ReadableMap cifs){
- final Activity activity = getCurrentActivity();
- ApiConfig apiConfig = new ApiConfig.Builder().setCustomIssueFields(getCustomIssueFields(cifs)).build();
- Support.showFAQs(activity, apiConfig);
- }
-
- @ReactMethod
- public void requestUnreadMessagesCount(){
-
- // TODO: Is the correct place to create these?
- countErrorHandler = new Handler() {
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- }
- };
-
- countSuccessHandler = new Handler() {
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- Bundle countData = (Bundle) msg.obj;
- Integer count = countData.getInt("value");
- WritableMap params = Arguments.createMap();
- params.putInt("count", count);
- sendEvent(mReactContext, "didReceiveUnreadMessagesCount", params);
- }
- };
-
- Support.getNotificationCount(countSuccessHandler, countErrorHandler);
- }
-
- private void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params) {
- reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
- .emit(eventName, params);
- }
-
-
-
- private Map getCustomIssueFields(ReadableMap cifs) {
- ReadableMapKeySetIterator iterator = cifs.keySetIterator();
- Map customIssueFields = new HashMap<>();
-
- while (iterator.hasNextKey()) {
- String key = iterator.nextKey();
- ReadableArray array = cifs.getArray(key);
- customIssueFields.put(key, new String[]{array.getString(0), array.getString(1)});
- }
-
- return customIssueFields;
- }
-
- @Override
- public String getName() {
- return "RNHelpshift";
- }
+public class RNHelpshiftModule extends ReactContextBaseJavaModule implements Support.Delegate {
+
+ private final Application app;
+ private ReactApplicationContext mReactContext;
+ private Handler countSuccessHandler;
+ private Handler countErrorHandler;
+
+ public RNHelpshiftModule(ReactApplicationContext reactContext) {
+ super(reactContext);
+
+ mReactContext= reactContext;
+
+ this.app = (Application)reactContext.getApplicationContext();
+ }
+ @Override
+ public String getName() {
+ return "RNHelpshift";
+ }
+
+ @ReactMethod
+ public void init(String key, String domain, String appid) throws InstallException {
+ Map extras = new HashMap<>();
+ extras.put("manualLifecycleTracking", true);
+ extras.put("enableDefaultConversationalFiling", true);
+ InstallConfig installConfig = new InstallConfig.Builder().setExtras(extras).build();
+
+ Core.init(Support.getInstance());
+ Core.install(this.app, key, domain, appid,installConfig);
+ CoreInternal.onAppForeground();
+ Support.setDelegate(this);
+ }
+
+ @ReactMethod
+ public void login(ReadableMap user){
+ HelpshiftUser userBuilder;
+ String email = user.hasKey("email") ? user.getString("email") : null;
+ String identifier = user.hasKey("identifier") ? user.getString("identifier") : null;
+ if(user.hasKey("name") && user.hasKey("authToken")) {
+ userBuilder = new HelpshiftUser.Builder(identifier, email)
+ .setName(user.getString("name"))
+ .setAuthToken(user.getString("authToken"))
+ .build();
+ } else if (user.hasKey("name")) {
+ userBuilder = new HelpshiftUser.Builder(identifier, email)
+ .setName(user.getString("name"))
+ .build();
+ } else if (user.hasKey("authToken")) {
+ userBuilder = new HelpshiftUser.Builder(identifier, email)
+ .setAuthToken(user.getString("authToken"))
+ .build();
+ } else {
+ userBuilder = new HelpshiftUser.Builder(identifier, email).build();
+ }
+
+ Core.login(userBuilder);
+ }
+
+ @ReactMethod
+ public void logout(){
+ Core.logout();
+ }
+
+ @ReactMethod
+ public void showConversation(){
+
+ final Activity activity = getCurrentActivity();
+ Support.showConversation(activity);
+ }
+
+ @ReactMethod
+ public void showConversationWithCIFs(ReadableMap cifs){
+
+ final Activity activity = getCurrentActivity();
+ ApiConfig apiConfig = new ApiConfig.Builder().setCustomIssueFields(getCustomIssueFields(cifs)).build();
+ Support.showConversation(activity, apiConfig);
+ }
+
+ @ReactMethod
+ public void showFAQs(){
+ final Activity activity = getCurrentActivity();
+ Support.showFAQs(activity);
+ }
+
+ @ReactMethod
+ public void showFAQsWithCIFs(ReadableMap cifs){
+ final Activity activity = getCurrentActivity();
+ ApiConfig apiConfig = new ApiConfig.Builder().setCustomIssueFields(getCustomIssueFields(cifs)).build();
+ Support.showFAQs(activity, apiConfig);
+ }
+
+ @ReactMethod
+ public void requestUnreadMessagesCount(){
+
+ // TODO: Is the correct place to create these?
+ countErrorHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
+ }
+ };
+
+ countSuccessHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
+ Bundle countData = (Bundle) msg.obj;
+ Integer count = countData.getInt("value");
+ WritableMap params = Arguments.createMap();
+ params.putInt("count", count);
+ sendEvent(mReactContext, "Helpshift/DidReceiveUnreadMessagesCount", params);
+ }
+ };
+
+ Support.getNotificationCount(countSuccessHandler, countErrorHandler);
+ }
+
+ private void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params) {
+ reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
+ .emit(eventName, params);
+ }
+
+ private Map getCustomIssueFields(ReadableMap cifs) {
+ ReadableMapKeySetIterator iterator = cifs.keySetIterator();
+ Map customIssueFields = new HashMap<>();
+
+ while (iterator.hasNextKey()) {
+ String key = iterator.nextKey();
+ ReadableArray array = cifs.getArray(key);
+ customIssueFields.put(key, new String[]{array.getString(0), array.getString(1)});
+ }
+
+ return customIssueFields;
+ }
+
+ @Override
+ public void sessionBegan() {
+ Log.d("Helpshift", "sessionBegan");
+ sendEvent(mReactContext, "Helpshift/SessionBegan", Arguments.createMap());
+ }
+
+ @Override
+ public void sessionEnded() {
+ Log.d("Helpshift", "sessionEnded");
+ sendEvent(mReactContext, "Helpshift/SessionEnded", Arguments.createMap());
+ }
+
+ @Override
+ public void newConversationStarted(String newConversationMessage) {
+ Log.d("Helpshift", "newConversationStarted");
+ WritableMap params = Arguments.createMap();
+ params.putString("newConversationMessage", newConversationMessage);
+ sendEvent(mReactContext, "Helpshift/NewConversationStarted", params);
+ }
+
+ @Override
+ public void conversationEnded() {
+ Log.d("Helpshift", "conversationEnded");
+ sendEvent(mReactContext, "Helpshift/ConversationEnded", Arguments.createMap());
+ }
+
+ @Override
+ public void userRepliedToConversation(String newMessage) {
+ Log.d("Helpshift", "userRepliedToConversation");
+ WritableMap params = Arguments.createMap();
+ params.putString("newMessage", newMessage);
+ sendEvent(mReactContext, "Helpshift/UserRepliedToConversation", params);
+ }
+
+ @Override
+ public void userCompletedCustomerSatisfactionSurvey(int rating, String feedback) {
+ Log.d("Helpshift", "userCompletedCustomerSatisfactionSurvey");
+ WritableMap params = Arguments.createMap();
+ params.putInt("rating", rating);
+ params.putString("feedback", feedback);
+ sendEvent(mReactContext, "Helpshift/UserCompletedCustomerSatisfactionSurvey", params);
+ }
+
+
+ //TODO: determine if File can be sent by React Native bridge
+ @Override
+ public void displayAttachmentFile(Uri attachmentFile) { }
+
+ // TODO: determine if File can be sent by React Native bridge
+ @Override
+ public void displayAttachmentFile(File attachmentFile) {}
+
+ @Override
+ public void didReceiveNotification(int count) {
+ Log.d("Helpshift", "didReceiveNotification");
+ WritableMap params = Arguments.createMap();
+ params.putInt("count", count);
+ sendEvent(mReactContext, "Helpshift/DidReceiveNotification", params);
+ }
+
+ @Override
+ public void authenticationFailed(HelpshiftUser user, AuthenticationFailureReason reason) {
+ Log.d("Helpshift", "authenticationFailed");
+ WritableMap params = Arguments.createMap();
+ params.putString("user", user.toString());
+ params.putString("reason", reason.toString());
+ sendEvent(mReactContext, "Helpshift/AuthenticationFailed", params);
+ }
}
\ No newline at end of file
diff --git a/android/src/main/java/com/reactlibrary/RNHelpshiftPackage.java b/android/src/main/java/com/reactlibrary/RNHelpshiftPackage.java
index 8c7fa76..f5cabc9 100644
--- a/android/src/main/java/com/reactlibrary/RNHelpshiftPackage.java
+++ b/android/src/main/java/com/reactlibrary/RNHelpshiftPackage.java
@@ -1,5 +1,5 @@
-package com.reactlibrary;
+package com.helpshift.reactlibrary;
import java.util.Arrays;
import java.util.Collections;
diff --git a/android/src/main/java/com/reactlibrary/RNHelpshiftView.java b/android/src/main/java/com/reactlibrary/RNHelpshiftView.java
index 48e2afd..96a6983 100644
--- a/android/src/main/java/com/reactlibrary/RNHelpshiftView.java
+++ b/android/src/main/java/com/reactlibrary/RNHelpshiftView.java
@@ -1,12 +1,18 @@
-package com.reactlibrary;
+package com.helpshift.reactlibrary;
+import android.app.Activity;
import android.app.Application;
-import android.content.Context;
-import android.graphics.Color;
+import android.net.Uri;
import android.util.Log;
-import android.widget.FrameLayout;
+import android.view.View;
+import android.view.ViewTreeObserver;
import android.widget.LinearLayout;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableArray;
@@ -14,12 +20,14 @@
import com.facebook.react.bridge.ReadableMapKeySetIterator;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
-import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.react.uimanager.ViewGroupManager;
import com.facebook.react.uimanager.annotations.ReactProp;
+import com.facebook.react.views.view.ReactViewGroup;
import com.helpshift.Core;
+import com.helpshift.CoreInternal;
import com.helpshift.HelpshiftUser;
-import com.helpshift.activities.MainActivity;
+import com.helpshift.InstallConfig;
import com.helpshift.delegate.AuthenticationFailureReason;
import com.helpshift.exceptions.InstallException;
import com.helpshift.support.ApiConfig;
@@ -29,13 +37,7 @@
import java.util.HashMap;
import java.util.Map;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentActivity;
-
-public class RNHelpshiftView extends SimpleViewManager implements Support.Delegate {
+public class RNHelpshiftView extends ViewGroupManager implements Support.Delegate {
public static final String REACT_CLASS = "RNTHelpshift";
@@ -48,40 +50,65 @@ public String getName() {
}
@Override
- public FrameLayout createViewInstance(ThemedReactContext context) {
- FrameLayout frameLayout = new FrameLayout(context);
-
+ public ReactViewGroup createViewInstance(ThemedReactContext context) {
+ final ReactViewGroup reactView = new ReactViewGroup(context);
mReactContext = context;
-
mApplication = (Application)context.getApplicationContext();
-
- return frameLayout;
+ return reactView;
}
@ReactProp(name = "config")
- public void setConfig(FrameLayout frameLayout, ReadableMap config) throws InstallException {
- Support.setDelegate(this);
+ public void setConfig(final ReactViewGroup reactView, ReadableMap config) {
+ Map extras = new HashMap<>();
+ extras.put("manualLifecycleTracking", true);
+ extras.put("enableDefaultConversationalFiling", true);
+ InstallConfig installConfig = new InstallConfig.Builder().setExtras(extras).build();
+
+
Core.init(Support.getInstance());
- Core.install(mApplication, config.getString("apiKey"), config.getString("domain"), config.getString("appId"));
+
+ try {
+ Core.install(mApplication, config.getString("apiKey"), config.getString("domain"), config.getString("appId"), installConfig);
+ CoreInternal.onAppForeground();
+ } catch (InstallException e) {
+ Log.e("Helpshift", "invalid install credentials : ", e);
+ }
if (config.hasKey("user")) {
this.login(config.getMap("user"));
}
-
-
- // TODO: USE FRAGMENT INSTEAD
+ Support.setDelegate(this);
+
+ Activity activity = mReactContext.getCurrentActivity();
+ final FragmentManager fragmentManager = ((AppCompatActivity)activity).getSupportFragmentManager();
+ final Fragment helpshiftFragment;
+;
+
if (config.hasKey("cifs")) {
ApiConfig apiConfig = new ApiConfig.Builder().setCustomIssueFields(getCustomIssueFields(config.getMap("cifs"))).build();
Support.showConversation(mReactContext.getCurrentActivity(), apiConfig);
+
} else {
Support.showConversation(mReactContext.getCurrentActivity());
+
}
- // Fragment helpshiftFragment = Support.getConversationFragment(mReactContext.getCurrentActivity());
- // mReactContext.getCurrentActivity().getFragmentManager().beginTransaction().add(frameLayout.getId(), helpshiftFragment).commit();
- // LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(0, 0);
- // frameLayout.setLayoutParams(lp);
- // frameLayout.setBackgroundColor(Color.parseColor("purple"));
+ LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(0, 0);
+
+
+ reactView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ fragmentManager.executePendingTransactions();
+ for (int i = 0; i < reactView.getChildCount(); i++) {
+ View child = reactView.getChildAt(i);
+ child.measure(View.MeasureSpec.makeMeasureSpec(reactView.getMeasuredWidth(), View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(reactView.getMeasuredHeight(), View.MeasureSpec.EXACTLY));
+ child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());
+ }
+ }
+ });
+
}
private void login(ReadableMap user){
@@ -154,7 +181,7 @@ public void conversationEnded() {
@Override
public void userRepliedToConversation(String newMessage) {
- Log.d("Helpshift", "newConversationStarted");
+ Log.d("Helpshift", "userRepliedToConversation");
WritableMap params = Arguments.createMap();
params.putString("newMessage", newMessage);
sendEvent(mReactContext, "Helpshift/UserRepliedToConversation", params);
@@ -170,14 +197,13 @@ public void userCompletedCustomerSatisfactionSurvey(int rating, String feedback)
}
-// TODO: determine if File can be sent by React Native bridge
+ //TODO: determine if File can be sent by React Native bridge
@Override
- public void displayAttachmentFile(File attachmentFile) {
-// Log.d("Helpshift", "displayAttachmentFile");
-// WritableMap params = Arguments.createMap();
-// params.putString("attachmentFile", attachmentFile.toString());
-// sendEvent(mReactContext, "Helpshift/DisplayAttachmentFile", params);
- }
+ public void displayAttachmentFile(Uri attachmentFile) { }
+
+ // TODO: determine if File can be sent by React Native bridge
+ @Override
+ public void displayAttachmentFile(File attachmentFile) {}
@Override
public void didReceiveNotification(int newMessagesCount) {
diff --git a/android/src/main/res/values/styles.xml b/android/src/main/res/values/styles.xml
new file mode 100644
index 0000000..e50c259
--- /dev/null
+++ b/android/src/main/res/values/styles.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dist/index.d.ts b/dist/index.d.ts
new file mode 100644
index 0000000..5383d43
--- /dev/null
+++ b/dist/index.d.ts
@@ -0,0 +1,39 @@
+import React from "react";
+import { ViewStyle } from "react-native";
+interface HelpshiftUser {
+ authToken: string;
+ identifier: string;
+ name: string;
+ email: string;
+}
+interface HelpshiftConfig {
+ user: HelpshiftUser;
+ cifs: object;
+ apiKey: string;
+ domain: string;
+ appId: string;
+ width: number;
+ height: number;
+}
+interface HelpshiftProps {
+ config: HelpshiftConfig;
+ style?: ViewStyle;
+}
+declare function isHelpshiftAvailable(): boolean;
+declare class Helpshift extends React.PureComponent {
+ render(): JSX.Element;
+ static init: (apiKey: string, domain: string, appId: string) => any;
+ static login: (user: HelpshiftUser) => any;
+ static logout: () => any;
+ static requestUnreadMessagesCount: () => any;
+ static showConversationWithCIFs: (cifs: object) => any;
+ static showConversation: () => any;
+ static isAvailable: typeof isHelpshiftAvailable;
+ static eventEmitter: import("react-native").EventEmitter | {
+ once: () => void;
+ addListener: () => void;
+ removeListener: () => void;
+ removeAllListeners: () => void;
+ };
+}
+export default Helpshift;
diff --git a/dist/index.js b/dist/index.js
new file mode 100644
index 0000000..87b0ba2
--- /dev/null
+++ b/dist/index.js
@@ -0,0 +1,49 @@
+import React from "react";
+import { NativeEventEmitter, NativeModules, requireNativeComponent, View } from "react-native";
+function isHelpshiftAvailable() {
+ return "RNTHelpshift" in NativeModules.UIManager;
+}
+function getHelp() {
+ if (isHelpshiftAvailable()) {
+ return requireNativeComponent("RNTHelpshift");
+ }
+ return View;
+}
+const RNTHelpshift = getHelp();
+const { RNHelpshift } = NativeModules;
+const mockEmitter = {
+ once: () => console.warn(MODULE_UNAVAILABLE_WARNING),
+ addListener: () => console.warn(MODULE_UNAVAILABLE_WARNING),
+ removeListener: () => console.warn(MODULE_UNAVAILABLE_WARNING),
+ removeAllListeners: () => console.warn(MODULE_UNAVAILABLE_WARNING)
+};
+const MODULE_UNAVAILABLE_WARNING = "Native module unavailable in project binary.";
+class Helpshift extends React.PureComponent {
+ render() {
+ return ;
+ }
+}
+Helpshift.init = (apiKey, domain, appId) => RNHelpshift
+ ? RNHelpshift.init(apiKey, domain, appId)
+ : console.warn(MODULE_UNAVAILABLE_WARNING);
+// TODO: Rerender Helpshift view on iOS if using
+Helpshift.login = (user) => RNHelpshift
+ ? RNHelpshift.login(user)
+ : console.warn(MODULE_UNAVAILABLE_WARNING);
+Helpshift.logout = () => RNHelpshift
+ ? RNHelpshift.logout()
+ : console.warn(MODULE_UNAVAILABLE_WARNING);
+Helpshift.requestUnreadMessagesCount = () => RNHelpshift
+ ? RNHelpshift.requestUnreadMessagesCount()
+ : console.warn(MODULE_UNAVAILABLE_WARNING);
+Helpshift.showConversationWithCIFs = (cifs) => RNHelpshift
+ ? RNHelpshift.showConversationWithCIFs(cifs)
+ : console.warn(MODULE_UNAVAILABLE_WARNING);
+Helpshift.showConversation = () => RNHelpshift
+ ? RNHelpshift.showConversation()
+ : console.warn(MODULE_UNAVAILABLE_WARNING);
+Helpshift.isAvailable = isHelpshiftAvailable;
+Helpshift.eventEmitter = RNHelpshift
+ ? new NativeEventEmitter(RNHelpshift)
+ : mockEmitter;
+export default Helpshift;
diff --git a/helpshift-react-native.podspec b/helpshift-react-native.podspec
index 42f6cde..70009ff 100644
--- a/helpshift-react-native.podspec
+++ b/helpshift-react-native.podspec
@@ -16,5 +16,5 @@ Pod::Spec.new do |s|
s.source_files = "ios/**/*.{h,m}"
s.dependency 'React'
- s.dependency "Helpshift", "7.6.2"
+ s.dependency "Helpshift", "7.11.2"
end
\ No newline at end of file
diff --git a/index.js b/index.js
deleted file mode 100644
index f54bc4b..0000000
--- a/index.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import React from 'react';
-import {
- NativeModules,
- NativeEventEmitter,
- requireNativeComponent
-} from 'react-native';
-import PropTypes from 'prop-types';
-
-class Helpshift extends React.Component {
- render() {
- return ;
- }
-}
-
-Helpshift.propTypes = {
- config: PropTypes.shape({
- apiKey: PropTypes.string.isRequired,
- domain: PropTypes.string.isRequired,
- appId: PropTypes.string.isRequired,
- height: PropTypes.number,
- width: PropTypes.number,
- user: PropTypes.shape({
- identifier: PropTypes.string.isRequired,
- email: PropTypes.string,
- name: PropTypes.string,
- authToken: PropTypes.string
- }),
- cifs: PropTypes.object
- }).isRequired
-};
-
-const { RNHelpshift } = NativeModules;
-
-const HelpshiftEventEmitter = Helpshift.eventEmitter = new NativeEventEmitter(RNHelpshift);
-
-Helpshift.init = (apiKey, domain, appId) => RNHelpshift.init(apiKey, domain, appId);
-
-// TODO: Rerender Helpshift view on iOS if using
-Helpshift.login = user => RNHelpshift.login(user)
-
-Helpshift.logout = user => RNHelpshift.logout();
-
-Helpshift.showConversation = () => RNHelpshift.showConversation();
-
-Helpshift.showFAQs = () => RNHelpshift.showFAQs();
-
-Helpshift.showConversationWithCIFs = cifs => RNHelpshift.showConversationWithCIFs(cifs);
-
-Helpshift.showFAQsWithCIFs = cifs => RNHelpshift.showFAQsWithCIFs(cifs);
-
-Helpshift.requestUnreadMessagesCount = () => {
- return new Promise((resolve, reject) => {
- const subscription = HelpshiftEventEmitter.addListener('Helpshift/DidReceiveUnreadMessagesCount',
- ({ count }) => {
- resolve(count);
- subscription.remove();
- }
- );
-
- RNHelpshift.requestUnreadMessagesCount();
- });
-}
-
-var RNTHelpshift = requireNativeComponent('RNTHelpshift', Helpshift);
-
-export default Helpshift;
\ No newline at end of file
diff --git a/index.tsx b/index.tsx
new file mode 100644
index 0000000..3e71d4e
--- /dev/null
+++ b/index.tsx
@@ -0,0 +1,99 @@
+import React from "react";
+import {
+ NativeEventEmitter,
+ NativeModules,
+ requireNativeComponent,
+ View,
+ ViewStyle
+} from "react-native";
+
+interface HelpshiftUser {
+ authToken: string;
+ identifier: string;
+ name: string;
+ email: string;
+}
+
+interface HelpshiftConfig {
+ user: HelpshiftUser;
+ cifs: object;
+ apiKey: string;
+ domain: string;
+ appId: string;
+ width: number;
+ height: number;
+}
+
+interface HelpshiftProps {
+ config: HelpshiftConfig;
+ style?: ViewStyle;
+}
+
+function isHelpshiftAvailable() {
+ return "RNTHelpshift" in NativeModules.UIManager;
+}
+
+function getHelp() {
+ if (isHelpshiftAvailable()) {
+ return requireNativeComponent("RNTHelpshift");
+ }
+ return View;
+}
+
+const RNTHelpshift = getHelp();
+const { RNHelpshift } = NativeModules;
+
+const mockEmitter = {
+ once: () => console.warn(MODULE_UNAVAILABLE_WARNING),
+ addListener: () => console.warn(MODULE_UNAVAILABLE_WARNING),
+ removeListener: () => console.warn(MODULE_UNAVAILABLE_WARNING),
+ removeAllListeners: () => console.warn(MODULE_UNAVAILABLE_WARNING)
+};
+
+const MODULE_UNAVAILABLE_WARNING =
+ "Native module unavailable in project binary.";
+
+class Helpshift extends React.PureComponent {
+ render() {
+ return ;
+ }
+
+ static init = (apiKey: string, domain: string, appId: string) =>
+ RNHelpshift
+ ? RNHelpshift.init(apiKey, domain, appId)
+ : console.warn(MODULE_UNAVAILABLE_WARNING);
+
+ // TODO: Rerender Helpshift view on iOS if using
+ static login = (user: HelpshiftUser) =>
+ RNHelpshift
+ ? RNHelpshift.login(user)
+ : console.warn(MODULE_UNAVAILABLE_WARNING);
+
+ static logout = () =>
+ RNHelpshift
+ ? RNHelpshift.logout()
+ : console.warn(MODULE_UNAVAILABLE_WARNING);
+
+ static requestUnreadMessagesCount = () =>
+ RNHelpshift
+ ? RNHelpshift.requestUnreadMessagesCount()
+ : console.warn(MODULE_UNAVAILABLE_WARNING);
+
+ static showConversationWithCIFs = (cifs: object) =>
+ RNHelpshift
+ ? RNHelpshift.showConversationWithCIFs(cifs)
+ : console.warn(MODULE_UNAVAILABLE_WARNING);
+
+ static showConversation = () =>
+ RNHelpshift
+ ? RNHelpshift.showConversation()
+ : console.warn(MODULE_UNAVAILABLE_WARNING);
+
+ static isAvailable = isHelpshiftAvailable;
+
+ static eventEmitter = RNHelpshift
+ ? new NativeEventEmitter(RNHelpshift)
+ : mockEmitter;
+}
+
+export default Helpshift;
diff --git a/ios/RNHelpshift.h b/ios/RNHelpshift.h
index 2fec2a8..e13ad93 100644
--- a/ios/RNHelpshift.h
+++ b/ios/RNHelpshift.h
@@ -1,6 +1,6 @@
-#import "RCTBridgeModule.h"
-#import "RCTEventEmitter.h"
+#import
+#import
#import "HelpshiftSupport.h"
@interface RNHelpshift : RCTEventEmitter
diff --git a/ios/RNHelpshift.m b/ios/RNHelpshift.m
index da53fcf..844a090 100644
--- a/ios/RNHelpshift.m
+++ b/ios/RNHelpshift.m
@@ -1,11 +1,10 @@
-#import "RCTLog.h"
-#import "RCTViewManager.h"
-#import "RCTBridgeModule.h"
-#import "RCTEventEmitter.h"
+#import
+#import
+#import
+#import
#import "RNHelpshift.h"
-
#import "HelpshiftCore.h"
#import "HelpshiftSupport.h"
@@ -13,7 +12,16 @@ @implementation RNHelpshift
-(id) init {
self = [super init];
+ HelpshiftInstallConfigBuilder *installConfigBuilder = [[HelpshiftInstallConfigBuilder alloc] init];
+ installConfigBuilder.enableAutomaticThemeSwitching = NO;
+ [HelpshiftCore initializeWithProvider:[HelpshiftSupport sharedInstance]];
+
+ NSString *apiKey = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"helpshiftApiKey"];
+ NSString *domainName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"helpshiftDomainName"];
+ NSString *appID = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"helpshiftAppID"];
+ [HelpshiftCore installForApiKey:apiKey domainName:domainName appID:appID withConfig:installConfigBuilder.build];
[[HelpshiftSupport sharedInstance] setDelegate:self];
+ [HelpshiftSupport pauseDisplayOfInAppNotification:YES];
return self;
}
@@ -32,8 +40,7 @@ + (BOOL)requiresMainQueueSetup
RCT_EXPORT_METHOD(init:(NSString *)apiKey domain:(NSString *)domain appId:(NSString *)appId)
{
- [HelpshiftCore initializeWithProvider:[HelpshiftSupport sharedInstance]];
- [HelpshiftCore installForApiKey:apiKey domainName:domain appID:appId];
+ // Ignored on iOS
}
RCT_EXPORT_METHOD(login:(NSDictionary *)user)
@@ -158,10 +165,13 @@ @implementation RNTHelpshiftManager
RCT_EXPORT_MODULE(RNTHelpshift)
RCT_CUSTOM_VIEW_PROPERTY(config, NSDictionary, RNTHelpshiftManager) {
+ HelpshiftInstallConfigBuilder *installConfigBuilder = [[HelpshiftInstallConfigBuilder alloc] init];
+ installConfigBuilder.enableAutomaticThemeSwitching = NO;
[HelpshiftCore initializeWithProvider:[HelpshiftSupport sharedInstance]];
[HelpshiftCore installForApiKey:json[@"apiKey"]
domainName:json[@"domain"]
- appID:json[@"appId"]];
+ appID:json[@"appId"]
+ withConfig:installConfigBuilder.build];
// Log user in if identified
if (json[@"user"]) {
@@ -177,11 +187,12 @@ @implementation RNTHelpshiftManager
// Add CIFS if existing
if (json[@"cifs"]) builder.customIssueFields = json[@"cifs"];
[HelpshiftSupport conversationViewControllerWithConfig:[builder build] completion:^(UIViewController *conversationVC) {
- UIViewController *rootController = UIApplication.sharedApplication.delegate.window.rootViewController;
-
+ UIViewController *rootController = [self currentViewController];
+
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:conversationVC];
[navController willMoveToParentViewController:rootController];
-
+ [navController.navigationBar setHidden:YES];
+
if (json[@"height"] && json[@"width"]) {
float height = [json[@"height"] floatValue];
float width = [json[@"width"] floatValue];
@@ -194,6 +205,30 @@ @implementation RNTHelpshiftManager
}];
}
+- (UIViewController *)currentViewController {
+ UIViewController *controller = [[[UIApplication sharedApplication] keyWindow] rootViewController];
+ UIViewController *presentedController = controller.presentedViewController;
+
+ while (presentedController && ![presentedController isBeingDismissed]) {
+ controller = presentedController;
+ presentedController = controller.presentedViewController;
+ }
+
+ // For Expo client, use the same logic as in ExpoKit currentViewController but this isn't a unimodule
+ // so adapt it for here
+ if ([controller respondsToSelector:@selector(contentViewController)]) {
+ UIViewController *contentController = [controller performSelector:@selector(contentViewController)];
+ if (contentController != nil) {
+ controller = contentController;
+ while (controller.presentedViewController != nil) {
+ controller = controller.presentedViewController;
+ }
+ }
+ }
+
+ return controller;
+}
+
- (UIView *)view
{
UIView *view = [[UIView alloc] init];
@@ -202,4 +237,3 @@ - (UIView *)view
}
@end
-
diff --git a/package.json b/package.json
index 898d546..36df4c6 100644
--- a/package.json
+++ b/package.json
@@ -1,11 +1,12 @@
{
"name": "helpshift-react-native",
- "version": "7.6.2",
+ "version": "7.8.0",
"description": "Helpshift React Native wrapper",
"homepage": "https://github.com/readehelpshift/helpshift-react-native",
- "main": "index.js",
+ "main": "dist/index.js",
+ "types": "dist/index.d.ts",
"scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
+ "build": "tsc"
},
"keywords": [
"react-native"
@@ -13,9 +14,11 @@
"author": "Reade Lobdill",
"license": "",
"peerDependencies": {
+ "react": "16.9.0",
"react-native": "^0.41.2"
},
- "dependencies": {
- "prop-types": "^15.7.2"
+ "devDependencies": {
+ "@types/react-native": "^0.57.38",
+ "typescript": "^3.3.1"
}
}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..2865fc9
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,13 @@
+{
+ "compilerOptions": {
+ "jsx": "react-native",
+ "target": "es2017",
+ "module": "es2015",
+ "lib": ["es2017", "dom"],
+ "declaration": true,
+ "outDir": "dist",
+ "strict": true,
+ "esModuleInterop": true
+ },
+ "exclude": ["node_modules", "dist"]
+}
diff --git a/yarn.lock b/yarn.lock
index f19b43a..b5e6cb6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,33 +2,33 @@
# yarn lockfile v1
-"js-tokens@^3.0.0 || ^4.0.0":
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
- integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+"@types/prop-types@*":
+ version "15.7.3"
+ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
+ integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
-loose-envify@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
- integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
+"@types/react-native@^0.57.38":
+ version "0.57.65"
+ resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.57.65.tgz#9da4773aaa95924bce42a54a5c19cfd8ffd5022b"
+ integrity sha512-7P5ulTb+/cnwbABWaAjzKmSYkRWeK7UCTfUwHhDpnwxdiL2X/KbdN1sPgo0B2E4zxfYE3MEoHv7FhB8Acfvf8A==
dependencies:
- js-tokens "^3.0.0 || ^4.0.0"
+ "@types/prop-types" "*"
+ "@types/react" "*"
-object-assign@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
- integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
-
-prop-types@^15.7.2:
- version "15.7.2"
- resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
- integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
+"@types/react@*":
+ version "16.9.17"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.17.tgz#58f0cc0e9ec2425d1441dd7b623421a867aa253e"
+ integrity sha512-UP27In4fp4sWF5JgyV6pwVPAQM83Fj76JOcg02X5BZcpSu5Wx+fP9RMqc2v0ssBoQIFvD5JdKY41gjJJKmw6Bg==
dependencies:
- loose-envify "^1.4.0"
- object-assign "^4.1.1"
- react-is "^16.8.1"
+ "@types/prop-types" "*"
+ csstype "^2.2.0"
+
+csstype@^2.2.0:
+ version "2.6.8"
+ resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.8.tgz#0fb6fc2417ffd2816a418c9336da74d7f07db431"
+ integrity sha512-msVS9qTuMT5zwAGCVm4mxfrZ18BNc6Csd0oJAtiFMZ1FAx1CCvy2+5MDmYoix63LM/6NDbNtodCiGYGmFgO0dA==
-react-is@^16.8.1:
- version "16.10.1"
- resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.10.1.tgz#0612786bf19df406502d935494f0450b40b8294f"
- integrity sha512-BXUMf9sIOPXXZWqr7+c5SeOKJykyVr2u0UDzEf4LNGc6taGkQe1A9DFD07umCIXz45RLr9oAAwZbAJ0Pkknfaw==
+typescript@^3.3.1:
+ version "3.7.5"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae"
+ integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==