Skip to content

Commit 47be61d

Browse files
authored
Merge pull request #9 from botstar/feat/tu_add-widget-state
feat: 🎸 implement widget state (loaded, error)
2 parents bbf5fd6 + 3c8daf1 commit 47be61d

11 files changed

+85
-11
lines changed

.npmignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
examples/
2+
3+
# Logs
4+
*.log
5+
npm-debug.log
6+
7+
# Runtime data
8+
tmp
9+
build
10+
dist
11+
*.tgz
12+
13+
# Dependency directory
14+
node_modules/
15+
16+
.DS_Store

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export default function App() {
6666
onClosed={() => console.log('Widget closed')}
6767
onLoaded={() => console.log('Widget loaded')}
6868
onNewMessage={(message) => console.log('New message:', message)}
69+
onError={(message) => console.log('Error', message)}
6970
/>
7071
</View>
7172
);
@@ -85,6 +86,7 @@ export default function App() {
8586
| onClosed | () => void | No | Callback when the widget is closed |
8687
| onLoaded | () => void | No | Callback when the widget is loaded |
8788
| onNewMessage | () => void | No | Callback when a new message is received |
89+
| onError | (error:string) => void | No | Callback function triggered when an error occurs. |
8890
8991
## Methods
9092

examples/App.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Button, SafeAreaView, StyleSheet, View } from 'react-native';
44

55
export default function App() {
66
const chativeWidgetRef = useRef(null);
7-
const channelId = 's49f3a621-2f07-45a4-8019-92663014b998'; // Replace with your channel id
7+
const channelId = 's49f3a621-2f07-45a4-8019-92663014b997'; // Replace with your channel id
88

99
const handleOpenModal = () => {
1010
chativeWidgetRef.current.show();
@@ -22,6 +22,10 @@ export default function App() {
2222
console.log('onNewMessage');
2323
}
2424

25+
const onError = (error) => {
26+
console.log('Error:', error);
27+
}
28+
2529
const user = {
2630
user_id: 'UNIQUE_USER_ID',
2731
user: {
@@ -44,6 +48,7 @@ export default function App() {
4448
onLoaded={onLoaded}
4549
onClosed={handleCloseModal}
4650
onNewMessage={onNewMessage}
51+
onError={onError}
4752
/>
4853
</SafeAreaView>
4954
);

examples/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
"android": "expo start --android",
88
"ios": "expo start --ios",
99
"web": "expo start --web",
10-
"livechat": "yarn remove @chative.io/react-native-widget || true && yarn cache clean && yarn add ../chative.io-react-native-widget-v0.5.0.tgz"
10+
"livechat": "yarn remove @chative.io/react-native-widget || true && yarn cache clean && yarn add ../chative.io-react-native-widget-v0.5.1.tgz"
1111
},
1212
"dependencies": {
13-
"@chative.io/react-native-widget": "../chative.io-react-native-widget-v0.5.0.tgz",
13+
"@chative.io/react-native-widget": "../chative.io-react-native-widget-v0.5.1.tgz",
1414
"@react-native-async-storage/async-storage": "^1.23.1",
1515
"@types/react": "~18.2.79",
1616
"expo": "~51.0.20",

examples/yarn.lock

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -796,9 +796,9 @@
796796
"@babel/helper-validator-identifier" "^7.24.7"
797797
to-fast-properties "^2.0.0"
798798

799-
"@chative.io/react-native-widget@../chative.io-react-native-widget-v0.5.0.tgz":
800-
version "0.5.0"
801-
resolved "../chative.io-react-native-widget-v0.5.0.tgz#b074a980cd915570a5770b8a540949b47b951214"
799+
"@chative.io/react-native-widget@../chative.io-react-native-widget-v0.5.1.tgz":
800+
version "0.5.1"
801+
resolved "../chative.io-react-native-widget-v0.5.1.tgz#915eab11f56669755299544d916a25c03297064a"
802802

803803
"@expo/bunyan@^4.0.0":
804804
version "4.0.0"

index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ declare module '@chative.io/react-native-widget' {
2323
insetBottom?: number;
2424
onClosed?: () => void;
2525
onLoaded?: () => void;
26+
onError?: (error: any) => void;
2627
onNewMessage?: (message: any) => void;
2728
}
2829

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@chative.io/react-native-widget",
3-
"version": "0.5.0",
3+
"version": "0.5.2",
44
"description": "React Native SDK for Chative",
55
"main": "index.js",
66
"scripts": {

src/ChativeWidget.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const propTypes = {
1515
onClosed: PropTypes.func,
1616
onLoaded: PropTypes.func,
1717
onNewMessage: PropTypes.func,
18+
onError: PropTypes.func,
1819
};
1920

2021
const ChativeWidget = forwardRef(({
@@ -27,6 +28,7 @@ const ChativeWidget = forwardRef(({
2728
onClosed,
2829
onLoaded,
2930
onNewMessage,
31+
onError,
3032
}, ref) => {
3133
const [isModalVisible, setIsModalVisible] = useState(false);
3234
const webViewRef = useRef(null);
@@ -74,6 +76,7 @@ const ChativeWidget = forwardRef(({
7476
onLoaded={onLoaded}
7577
onNewMessage={onNewMessage}
7678
onClosedWidget={handleClose}
79+
onError={onError}
7780
/>
7881
</View>
7982
</SafeAreaView>

src/WebView.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,21 @@ import React, { forwardRef, useImperativeHandle, useRef } from 'react';
33
import { StyleSheet } from 'react-native';
44
import WebView from 'react-native-webview';
55
import { WIDGET_URL } from './constants';
6-
import { generateScript, safeParse } from './utils';
6+
import { generateScript, generateScriptGetError, safeParse } from './utils';
77

88
const propTypes = {
99
channelId: PropTypes.string.isRequired,
1010
user: PropTypes.object,
1111
onLoaded: PropTypes.func,
1212
onClosedWidget: PropTypes.func,
1313
onNewMessage: PropTypes.func,
14+
onError: PropTypes.func,
1415
};
1516

16-
const WebViewComponent = forwardRef(({ channelId, user, onLoaded, onClosedWidget, onNewMessage }, ref) => {
17+
const WebViewComponent = forwardRef(({ channelId, user, onLoaded, onClosedWidget, onNewMessage, onError }, ref) => {
1718
const webViewRef = useRef(null);
1819
const javascriptInit = React.useMemo(() => generateScript(user), [user]);
20+
const errorScript = React.useMemo(() => generateScriptGetError(), []);
1921

2022
useImperativeHandle(ref, () => ({
2123
injectJavaScript: (script) => {
@@ -30,12 +32,12 @@ const WebViewComponent = forwardRef(({ channelId, user, onLoaded, onClosedWidget
3032
<WebView
3133
ref={webViewRef}
3234
style={styles.webViewContainer}
35+
injectedJavaScript={errorScript}
3336
source={{
3437
uri: `${WIDGET_URL}/${channelId}?mode=livechat&state=${user ? 'off' : 'on'}`,
3538
}}
3639
onLoadEnd={() => {
3740
webViewRef.current?.injectJavaScript(javascriptInit);
38-
onLoaded && onLoaded();
3941
}}
4042
onMessage={(event) => {
4143
const { data } = event.nativeEvent;
@@ -48,6 +50,14 @@ const WebViewComponent = forwardRef(({ channelId, user, onLoaded, onClosedWidget
4850
if (parsedData.event === 'new-agent-message') {
4951
onNewMessage && onNewMessage();
5052
}
53+
54+
if (parsedData.event === 'ready') {
55+
onLoaded && onLoaded();
56+
}
57+
58+
if (parsedData.event === 'error') {
59+
onError && onError(parsedData.message);
60+
}
5161
}}
5262
/>
5363
);
@@ -61,4 +71,4 @@ const styles = StyleSheet.create({
6171

6272
WebViewComponent.propTypes = propTypes;
6373

64-
export default WebViewComponent;
74+
export default React.memo(WebViewComponent);

src/constants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export const COLOR_WHITE = '#fff';
22
export const INDEX_SHOW = 999;
33
export const INDEX_HIDE = -1;
44
export const WIDGET_URL = 'https://messenger.svc.chative.io/site';
5+
export const QUERY_URL = 'https://gateway.svc.chative.io/web/live/query';

src/utils.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { QUERY_URL, WIDGET_URL } from './constants';
12
export const generateScript = (user = {}) => {
23
const userString = safeStringify(user);
34
return `
@@ -25,9 +26,44 @@ export const generateScript = (user = {}) => {
2526
window.cti_api('addEventListener', { event: 'new-agent-message', callback: () => {
2627
window.ReactNativeWebView.postMessage(JSON.stringify({ event: 'new-agent-message' }));
2728
}});
29+
30+
window.cti_api('addEventListener', { event: 'ready', callback: () => {
31+
window.ReactNativeWebView.postMessage(JSON.stringify({ event: 'ready' }));
32+
}});
2833
`;
2934
};
3035

36+
export const generateScriptGetError = (channelId) => {
37+
return `
38+
function getTimeZone() {
39+
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
40+
return timeZone;
41+
}
42+
(function() {
43+
fetch("${QUERY_URL}", {
44+
method: 'POST',
45+
headers: {
46+
'Content-Type': 'application/json',
47+
},
48+
body: JSON.stringify({
49+
"app_id": "${channelId}",
50+
"user_id": "",
51+
"locale": "en-US",
52+
"timezone": getTimeZone(),
53+
"template": false,
54+
"host": "${WIDGET_URL}/${channelId}?mode=livechat"
55+
})
56+
}).then((response) => {
57+
if (response.status !== 200) {
58+
window.ReactNativeWebView.postMessage(JSON.stringify({ event: 'error', message: 'missing_config' }));
59+
}
60+
}).catch((error) => {
61+
window.ReactNativeWebView.postMessage(JSON.stringify({ event: 'error', data: error }));
62+
});
63+
})();
64+
`;
65+
}
66+
3167
export const WidgetApi = (event, data) => {
3268
return `
3369
window.cti_api('${event}', ${data});

0 commit comments

Comments
 (0)