@ada-support/react-native-sdk
Version:
The Ada ReactNative is a small framework that is used to embed your Ada Chat bot into your ReactNative application.
211 lines (183 loc) • 7.55 kB
JavaScript
import React from "react";
import {WebView} from 'react-native-webview';
import PropTypes from 'prop-types';
import {Platform, Linking, Image} from 'react-native';
const EMBED_URL_ANDROID = "file:///android_asset/embed.html"
const EMBED_URL = require('./android/src/main/assets/embed.html');
const RESOLVED_EMBED_ASSET = Image.resolveAssetSource(EMBED_URL);
const MESSAGE_SCRIPT_LOADED = `MESSAGE_SCRIPT_LOADED`
const MESSAGE_ADA_READY = `MESSAGE_ADA_READY`
const MESSAGE_CHATTER_AUTH = `MESSAGE_CHATTER_AUTH`
const MESSAGE_EVENT = `MESSAGE_EVENT`
const END_CONVERSATION_EVENT = `END_CONVERSATION_EVENT`
export default class AdaEmbedView extends React.Component {
actions = new Set();
static propTypes = {
handle: PropTypes.string,
cluster: PropTypes.string,
styles: PropTypes.string,
language: PropTypes.string,
greeting: PropTypes.string,
metaFields: PropTypes.object,
sensitiveMetaFields: PropTypes.object,
deviceToken: PropTypes.string,
thirdPartyCookiesEnabled: PropTypes.bool,
zdChatterAuthCallback: PropTypes.func,
eventCallbacks: PropTypes.object,
endConversationCallback: PropTypes.func
}
static defaultProps = {
handle: ``,
cluster: ``,
styles: ``,
language: ``,
greeting: ``,
metaFields: null,
sensitiveMetaFields: null,
deviceToken: ``,
thirdPartyCookiesEnabled: false,
zdChatterAuthCallback: null,
eventCallbacks: null,
endConversationCallback: () => {}
}
constructor(props) {
super(props);
this.state = {
isAdaReady: false
}
}
shouldOpenInline(requestUrl) {
const allowedUrls = ['embed.html', 'ada-instance-id', 'embed2', 'ada.support/embed/', 'ada-dev2.support/embed/'];
if(RESOLVED_EMBED_ASSET){
allowedUrls.push(RESOLVED_EMBED_ASSET.uri);
}
return allowedUrls.some(url => requestUrl.includes(url));
}
downloadTranscriptiOS(url){
if(Platform.OS == 'ios'){
let RNFetchBlob = require('rn-fetch-blob')
RNFetchBlob = RNFetchBlob.default
const dirs = RNFetchBlob.fs.dirs
const options = {
fileCache: true,
path : dirs.DocumentDir + '/chat_transcript.txt'
};
RNFetchBlob.config(options)
.fetch("GET", url)
.then(res => {
RNFetchBlob.ios.previewDocument(res.data);
}).catch((error) => {
console.log(error);
});
}
}
render() {
const source = Platform.OS === 'android' ? {uri: EMBED_URL_ANDROID} : EMBED_URL
return <WebView source={source}
domStorageEnabled={true}
allowUniversalAccessFromFileURLs={true}
thirdPartyCookiesEnabled={this.props.thirdPartyCookiesEnabled}
ref={ref => (this.webview = ref)}
onMessage={(event) => {
this.handleEvent(event)
}}
originWhitelist={[`*`]}
onShouldStartLoadWithRequest={request => {
if(request.url.includes("transcript/txt") && Platform.OS == 'ios'){
this.downloadTranscriptiOS(request.url)
return false;
} else if(!this.shouldOpenInline(request.url)){
Linking.openURL(request.url)
.catch(()=>{})
return false
}
return true
}}
/>
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
if (this.props.handle !== nextProps.handle ||
this.props.cluster !== nextProps.cluster ||
this.props.styles !== nextProps.styles ||
this.props.language !== nextProps.language ||
this.props.greeting !== nextProps.greeting ||
this.props.deviceToken != nextProps.deviceToken ||
JSON.stringify(this.props.metaFields) !== JSON.stringify(nextProps.metaFields) ||
JSON.stringify(this.props.sensitiveMetaFields) !== JSON.stringify(nextProps.sensitiveMetaFields)) {
this.state.isAdaReady = false
this.webview.reload()
}
return this.props.thirdPartyCookiesEnabled !== nextProps.thirdPartyCookiesEnabled
}
handleEvent = (event) => {
const eventData = JSON.parse(event.nativeEvent.data)
switch (eventData.name) {
case MESSAGE_SCRIPT_LOADED:
this.webview.injectJavaScript(this.#initializeEmbedScript(this.props));
break;
case MESSAGE_ADA_READY:
this.state.isAdaReady = true
this.actions.forEach((action) => {
this.#executeAction(action)
})
this.setDeviceToken(this.props.deviceToken);
this.actions.clear()
break;
case MESSAGE_CHATTER_AUTH:
if (this.props.zdChatterAuthCallback != null) {
this.props.zdChatterAuthCallback((token) => {
this.webview.injectJavaScript(`sendAuthToken("${token}")`);
})
}
break;
case MESSAGE_EVENT:
if (this.props.eventCallbacks != null) {
const eventCallback = this.props.eventCallbacks[eventData.data.event_name]
const defEventCallback = this.props.eventCallbacks["*"]
if (eventCallback != null) {
eventCallback(eventData.data)
}
if (defEventCallback != null) {
defEventCallback(eventData.data)
}
}
break;
case END_CONVERSATION_EVENT:
this.props.endConversationCallback(eventData.data)
break;
default:
break;
}
}
deleteHistory = () => {
this.#executeAction(`deleteHistory()`)
}
reset = (object) => {
this.#executeAction(`reset(${JSON.stringify(object)})`)
}
setMetaFields = (object) => {
this.#executeAction(`setMetaFields(${JSON.stringify(object)})`)
}
setSensitiveMetaFields = (object) => {
this.#executeAction(`setSensitiveMetaFields(${JSON.stringify(object)})`)
}
setDeviceToken = (object) => {
this.#executeAction(`setDeviceToken("${object}")`)
}
triggerAnswer = (object) => {
this.#executeAction(`triggerAnswer("${object}")`)
}
setLanguage = (language) => {
this.#executeAction(`setLanguage("${language}")`)
}
#executeAction = (action) => {
if (this.state.isAdaReady) {
this.webview.injectJavaScript(action);
} else {
this.actions.add(action)
}
}
#initializeEmbedScript = () => {
return `initializeEmbed("${this.props.handle}", "${this.props.cluster}", "${this.props.greeting}", "${this.props.styles}", "${this.props.language}", "${this.props.deviceToken}", ${JSON.stringify(this.props.metaFields)}, ${JSON.stringify(this.props.sensitiveMetaFields) })`
}
}