From 5d9b9cf05f2788520c146d0e410c031535a3e647 Mon Sep 17 00:00:00 2001 From: Ridho Ade Putra Date: Fri, 14 Mar 2025 03:13:42 +0700 Subject: [PATCH 1/9] Update constants.js --- src/constants.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/constants.js b/src/constants.js index d4240b6..c54cf01 100644 --- a/src/constants.js +++ b/src/constants.js @@ -2,6 +2,7 @@ export const WOOT_PREFIX = 'chatwoot-widget:'; export const POST_MESSAGE_EVENTS = { SET_LOCALE: 'set-locale', SET_CUSTOM_ATTRIBUTES: 'set-custom-attributes', + SET_CONVERSATION_CUSTOM_ATTRIBUTES: 'set-conversation-custom-attributes', SET_USER: 'set-user', SET_COLOR_SCHEME: 'set-color-scheme', }; From c284194679e61cf9828eea9f0d042960a0a4ab41 Mon Sep 17 00:00:00 2001 From: Ridho Ade Putra Date: Fri, 14 Mar 2025 03:15:57 +0700 Subject: [PATCH 2/9] Update utils.js --- src/utils.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/utils.js b/src/utils.js index 2a0fd87..a85fcea 100644 --- a/src/utils.js +++ b/src/utils.js @@ -46,6 +46,13 @@ export const generateScripts = ({ colorScheme, user, locale, customAttributes }) }; script += createWootPostMessage(attributeObject); } + if (customAttributes) { + const attributeObject = { + event: POST_MESSAGE_EVENTS.SET_CONVERSATION_CUSTOM_ATTRIBUTES, + customAttributes, + }; + script += createWootPostMessage(attributeObject); + } if (colorScheme) { const themeObject = { event: POST_MESSAGE_EVENTS.SET_COLOR_SCHEME, darkMode: colorScheme }; script += createWootPostMessage(themeObject); From a855b541225f55bb2c89fd065e476c7bc458d28f Mon Sep 17 00:00:00 2001 From: Ridho Ade Putra Date: Fri, 14 Mar 2025 03:19:08 +0700 Subject: [PATCH 3/9] Update WebView.js --- src/WebView.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/WebView.js b/src/WebView.js index 2f9de2d..4f1d1ff 100644 --- a/src/WebView.js +++ b/src/WebView.js @@ -16,6 +16,7 @@ const propTypes = { }), locale: PropTypes.string, customAttributes: PropTypes.shape({}), + conversationCustomAttributes: PropTypes.shape({}), closeModal: PropTypes.func, }; @@ -27,6 +28,7 @@ const WebViewComponent = ({ colorScheme = 'light', user = {}, customAttributes = {}, + conversationCustomAttributes = {}, closeModal, }) => { const [currentUrl, setCurrentUrl] = React.useState(null); @@ -40,6 +42,7 @@ const WebViewComponent = ({ locale, customAttributes, colorScheme, + conversationCustomAttributes }); const onShouldStartLoadWithRequest = (request) => { From 292999dbfcd8b22742e7e2a996554b38605874ad Mon Sep 17 00:00:00 2001 From: Ridho Ade Putra Date: Fri, 14 Mar 2025 03:19:51 +0700 Subject: [PATCH 4/9] Update utils.js --- src/utils.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils.js b/src/utils.js index a85fcea..7872b39 100644 --- a/src/utils.js +++ b/src/utils.js @@ -25,7 +25,7 @@ export const createWootPostMessage = (object) => { export const getMessage = (data) => data.replace(WOOT_PREFIX, ''); -export const generateScripts = ({ colorScheme, user, locale, customAttributes }) => { +export const generateScripts = ({ colorScheme, user, locale, customAttributes, conversationCustomAttributes }) => { let script = ''; if (user) { const userObject = { @@ -46,10 +46,10 @@ export const generateScripts = ({ colorScheme, user, locale, customAttributes }) }; script += createWootPostMessage(attributeObject); } - if (customAttributes) { + if (conversationCustomAttributes) { const attributeObject = { event: POST_MESSAGE_EVENTS.SET_CONVERSATION_CUSTOM_ATTRIBUTES, - customAttributes, + conversationCustomAttributes, }; script += createWootPostMessage(attributeObject); } From a645e199e6bb943bb08a65f7ab60f25e893fc444 Mon Sep 17 00:00:00 2001 From: Ridho Ade Putra Date: Fri, 14 Mar 2025 03:23:58 +0700 Subject: [PATCH 5/9] Update index.d.ts --- index.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/index.d.ts b/index.d.ts index dbebe49..372f341 100644 --- a/index.d.ts +++ b/index.d.ts @@ -17,6 +17,7 @@ declare module '@chatwoot/react-native-widget' { }; // This can actually be any object customAttributes?: Record; + conversationCustomAttributes?: Record; } class ChatWootWidget extends React.Component {} From cba21b4662ed36ab1949b67fbd26d06684f6709d Mon Sep 17 00:00:00 2001 From: Ridho Ade Putra Date: Fri, 14 Mar 2025 03:25:19 +0700 Subject: [PATCH 6/9] Update App.js --- src/App.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/App.js b/src/App.js index 0df600d..f6b864c 100644 --- a/src/App.js +++ b/src/App.js @@ -21,6 +21,7 @@ const propTypes = { locale: PropTypes.string, colorScheme: PropTypes.oneOf(['dark', 'light', 'auto']), customAttributes: PropTypes.shape({}), + conversationCustomAttributes: PropTypes.shape({}), closeModal: PropTypes.func, }; @@ -32,6 +33,7 @@ const ChatWootWidget = ({ locale = 'en', colorScheme = 'light', customAttributes = {}, + conversationCustomAttributes = {}, closeModal, }) => { const [cwCookie, setCookie] = useState(''); @@ -67,6 +69,7 @@ const ChatWootWidget = ({ locale={locale} colorScheme={colorScheme} customAttributes={customAttributes} + conversationCustomAttributes={conversationCustomAttributes} closeModal={closeModal} /> From a1d1f410bbfcd456eb078851171bde1d028dc442 Mon Sep 17 00:00:00 2001 From: Ridho Ade Putra Date: Sun, 27 Jul 2025 20:58:29 +0700 Subject: [PATCH 7/9] Update WebView.js --- src/WebView.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/WebView.js b/src/WebView.js index 4f1d1ff..74c6eed 100644 --- a/src/WebView.js +++ b/src/WebView.js @@ -1,5 +1,5 @@ import React from 'react'; -import { StyleSheet, Linking } from 'react-native'; +import { StyleSheet, Linking, View, ActivityIndicator } from 'react-native'; import { WebView } from 'react-native-webview'; import PropTypes from 'prop-types'; import { isJsonString, storeHelper, generateScripts, getMessage } from './utils'; @@ -61,6 +61,14 @@ const WebViewComponent = ({ const handleWebViewNavigationStateChange = (newNavState) => { setCurrentUrl(newNavState.url); }; + + const _renderLoading = () => { + return ( + + + + ) + } return ( { + setLoading(false); + }} + renderLoading={_renderLoading} /> ); }; From d3cdc42c0bcace9f0089680390a8d15e6f2a5925 Mon Sep 17 00:00:00 2001 From: Ridho Ade Putra Date: Sun, 27 Jul 2025 20:59:36 +0700 Subject: [PATCH 8/9] Update App.js --- src/App.js | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/App.js b/src/App.js index f6b864c..b5fb797 100644 --- a/src/App.js +++ b/src/App.js @@ -17,6 +17,7 @@ const propTypes = { avatar_url: PropTypes.string, email: PropTypes.string, identifier_hash: PropTypes.string, + user_id: PropTypes.number, }), locale: PropTypes.string, colorScheme: PropTypes.oneOf(['dark', 'light', 'auto']), @@ -52,15 +53,6 @@ const ChatWootWidget = ({ appColorScheme, }); return ( - - - - - ); }; From d3eb46ab0572e99266e25f623da086ba4bda2fda Mon Sep 17 00:00:00 2001 From: Ridho Ade Putra Date: Mon, 28 Jul 2025 01:00:32 +0700 Subject: [PATCH 9/9] Update WebView.js --- src/WebView.js | 129 +++++++++++++++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 48 deletions(-) diff --git a/src/WebView.js b/src/WebView.js index 74c6eed..5ac4b3c 100644 --- a/src/WebView.js +++ b/src/WebView.js @@ -1,5 +1,5 @@ -import React from 'react'; -import { StyleSheet, Linking, View, ActivityIndicator } from 'react-native'; +import React, { useState, useMemo } from 'react'; +import { StyleSheet, Linking, View, ActivityIndicator, Text } from 'react-native'; import { WebView } from 'react-native-webview'; import PropTypes from 'prop-types'; import { isJsonString, storeHelper, generateScripts, getMessage } from './utils'; @@ -12,11 +12,11 @@ const propTypes = { name: PropTypes.string, avatar_url: PropTypes.string, email: PropTypes.string, - identifier_hash: PropTypes.string, + identifier_hash: PropTypes.string,, + user_id: PropTypes.number, }), locale: PropTypes.string, customAttributes: PropTypes.shape({}), - conversationCustomAttributes: PropTypes.shape({}), closeModal: PropTypes.func, }; @@ -28,10 +28,10 @@ const WebViewComponent = ({ colorScheme = 'light', user = {}, customAttributes = {}, - conversationCustomAttributes = {}, closeModal, }) => { const [currentUrl, setCurrentUrl] = React.useState(null); + const [loading, setLoading] = useState(true); let widgetUrl = `${baseUrl}/widget?website_token=${websiteToken}&locale=${locale}`; if (cwCookie) { @@ -42,7 +42,6 @@ const WebViewComponent = ({ locale, customAttributes, colorScheme, - conversationCustomAttributes }); const onShouldStartLoadWithRequest = (request) => { @@ -61,57 +60,73 @@ const WebViewComponent = ({ const handleWebViewNavigationStateChange = (newNavState) => { setCurrentUrl(newNavState.url); }; - - const _renderLoading = () => { + + const opacity = useMemo(() => { + if (loading) { + return { + opacity: 0, + }; + } + return { + opacity: 1, + }; + }, [loading]); + + const renderLoadingComponent = () => { return ( - - + + + Loading... - ) - } + ); + }; return ( - { - const { data } = event.nativeEvent; - const message = getMessage(data); - if (isJsonString(message)) { - const parsedMessage = JSON.parse(message); - const { event: eventType, type } = parsedMessage; - if (eventType === 'loaded') { - const { - config: { authToken }, - } = parsedMessage; - storeHelper.storeCookie(authToken); - } - if (type === 'close-widget') { - closeModal(); + + { + const { data } = event.nativeEvent; + const message = getMessage(data); + if (isJsonString(message)) { + const parsedMessage = JSON.parse(message); + const { event: eventType, type } = parsedMessage; + if (eventType === 'loaded') { + const { + config: { authToken }, + } = parsedMessage; + storeHelper.storeCookie(authToken); + } + if (type === 'close-widget') { + closeModal(); + } } - } - }} - scalesPageToFit - useWebKit - sharedCookiesEnabled - javaScriptEnabled={true} - domStorageEnabled={true} - style={styles.WebViewStyle} - injectedJavaScript={injectedJavaScript} - onShouldStartLoadWithRequest={onShouldStartLoadWithRequest} - onNavigationStateChange={handleWebViewNavigationStateChange} - scrollEnabled - isLoading={isLoading} - onLoadEnd={()=>{ - setLoading(false); - }} - renderLoading={_renderLoading} - /> + }} + scalesPageToFit + useWebKit + sharedCookiesEnabled + javaScriptEnabled={true} + domStorageEnabled={true} + style={[styles.WebViewStyle, opacity]} + injectedJavaScript={injectedJavaScript} + onShouldStartLoadWithRequest={onShouldStartLoadWithRequest} + onNavigationStateChange={handleWebViewNavigationStateChange} + onLoadStart={() => setLoading(true)} + onLoadProgress={() => setLoading(true)} + onLoadEnd={() => setLoading(false)} + scrollEnabled + /> + {loading && renderLoadingComponent()} + ); }; const styles = StyleSheet.create({ + container: { + flex: 1, + }, modal: { flex: 1, borderRadius: 4, @@ -120,6 +135,24 @@ const styles = StyleSheet.create({ webViewContainer: { flex: 1, }, + WebViewStyle: { + flex: 1, + }, + loadingContainer: { + position: 'absolute', + top: 0, + left: 0, + right: 0, + bottom: 0, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: 'rgba(255, 255, 255, 0.9)', + }, + loadingText: { + marginTop: 10, + fontSize: 16, + color: '#666', + }, }); WebViewComponent.propTypes = propTypes; export default WebViewComponent;