Last active
January 4, 2025 04:58
-
-
Save hemantasapkota/2450abfe4641915dddebd1a74400dc65 to your computer and use it in GitHub Desktop.
Chatwoot React Native Widget Loading Indicator Fix
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, {useMemo, useState} from 'react'; | |
import {StyleSheet, Linking, Text, View} from 'react-native'; | |
import {isJsonString, storeHelper, generateScripts, getMessage} from './utils'; | |
import {WebView} from 'react-native-webview'; | |
export interface ChatWootWidgetProps { | |
websiteToken: string; | |
locale?: string; | |
baseUrl: string; | |
cwCookie: string; | |
colorScheme?: 'light' | 'auto' | 'dark'; | |
closeModal: () => void; | |
isLoading?: boolean; | |
user?: { | |
identifier?: string; | |
name?: string; | |
avatar_url?: string; | |
email?: string; | |
identifier_hash?: string; | |
}; | |
// This can actually be any object | |
customAttributes?: Record<string, unknown>; | |
} | |
export const ChatwootWidget = ({ | |
baseUrl, | |
websiteToken, | |
cwCookie = '', | |
locale = 'en', | |
colorScheme = 'light', | |
user = {}, | |
customAttributes = {}, | |
isLoading = false, | |
closeModal, | |
}: ChatWootWidgetProps) => { | |
const [loading, setLoading] = useState(isLoading); | |
const [currentUrl, setCurrentUrl] = React.useState(null); | |
let widgetUrl = `${baseUrl}/widget?website_token=${websiteToken}&locale=${locale}`; | |
if (cwCookie) { | |
widgetUrl = `${widgetUrl}&cw_conversation=${cwCookie}`; | |
} | |
const injectedJavaScript = generateScripts({ | |
user, | |
locale, | |
customAttributes, | |
colorScheme, | |
}); | |
const onShouldStartLoadWithRequest = request => { | |
const isMessageView = currentUrl && currentUrl.includes('#/messages'); | |
const isAttachmentUrl = !widgetUrl.includes(request.url); | |
// Open the attachments only in the external browser | |
const shouldRedirectToBrowser = isMessageView && isAttachmentUrl; | |
if (shouldRedirectToBrowser) { | |
Linking.openURL(request.url); | |
return false; | |
} | |
return true; | |
}; | |
const handleWebViewNavigationStateChange = (newNavState: any) => { | |
setCurrentUrl(newNavState.url); | |
}; | |
const opacity = useMemo(() => { | |
if (loading) { | |
return { | |
opacity: 1, | |
}; | |
} | |
return { | |
opacity: 1, | |
}; | |
}, [loading]); | |
return ( | |
<> | |
{loading && ( | |
<View className="flex-1 items-center justify-center"> | |
<Text>Please wait...</Text> | |
</View> | |
)} | |
<WebView | |
source={{ | |
uri: widgetUrl, | |
}} | |
onMessage={(event: any) => { | |
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.webViewContainer, opacity]} | |
injectedJavaScript={injectedJavaScript} | |
onShouldStartLoadWithRequest={onShouldStartLoadWithRequest} | |
onNavigationStateChange={handleWebViewNavigationStateChange} | |
onLoadStart={() => setLoading(true)} | |
onLoadProgress={() => setLoading(true)} | |
onLoadEnd={() => setLoading(false)} | |
scrollEnabled | |
/> | |
</> | |
); | |
}; | |
const styles = StyleSheet.create({ | |
modal: { | |
flex: 1, | |
borderRadius: 4, | |
overflow: 'hidden', | |
}, | |
webViewContainer: { | |
flex: 1, | |
backgroundColor: 'transparent', | |
}, | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@losh11 The remaining source code can be found in the chatwoot-react-native-widget repository. For your reference: