CMS Development

amjadg
メンバー

Embed Chat Into A ReactJS SPA

解決

So, is there an embed pattern to embed/integrate the chatbot into my reactJS SPA ? I couldn'y find an example or even an npm module for the chatbot. Is there a clean integration pattern for this into react ? Please share details.

1件の承認済みベストアンサー
kierana
解決策
投稿者

Embed Chat Into A ReactJS SPA

解決

Something like this should work:

 

// Create a hook to seperate out logic.
const useHubspotChat = (portalId) => { const [ hasLoaded, setHasLoaded ] = React.useState(false); const [ activeConversation, setActiveConversation ] = React.useState(false); const eventRef = React.useRef(null); React.useEffect(() => { console.log('hey') // Add event listener. window.hsConversationsOnReady = [() => { setHasLoaded(true); }]; // Create script component. let script = document.createElement('script'); script.src=`//js.hs-scripts.com/${portalId}.js`; script.async = true; document.body.appendChild(script); return () => { document.body.removeChild(script); window.hsConversationsOnReady = []; } }, []); // Subscripe to conversation events. React.useEffect(() => { eventRef.current = (payload) => { setActiveConversation(payload.conversation.conversationId); } if (hasLoaded) { window.HubSpotConversations.on( 'conversationStarted', eventRef.current); } return () => { window.HubSpotConversations.off('conversationStarted', eventRef.current); } }, [hasLoaded]); const openHandler = React.useCallback(() => { if (hasLoaded) { window.HubSpotConversations.widget.open(); } }, [hasLoaded]); const closeHandler = React.useCallback(() => { if (hasLoaded) { window.HubSpotConversations.widget.close(); } }, [hasLoaded]) return { hasLoaded, activeConversation, openHandler, closeHandler }; } const App = () => { const { hasLoaded, activeConversation, openHandler, closeHandler } = useHubspotChat(<portalidhere>); return ( <div> hi {hasLoaded ? 'yes': 'no'} conversation: { activeConversation } <button onClick={openHandler}>click me to open</button> <button onClick={closeHandler}>click me to close</button> </div>) } const rootElement = document.getElementById("root"); ReactDOM.render(<App />, rootElement);

 

元の投稿で解決策を見る

13件の返信
DLemesh
メンバー

Embed Chat Into A ReactJS SPA

解決

Just wanted to post my take on it.
I needed the ability to control the widget via a custom button in my app.

I created a provider for the widget and used CSS to show/hide the widget.

 

First and most important, is to make sure the widget won't load initally, so in the index.html you sould add this snippet at the end of the <body> tag:

<!-- Start of HubSpot Embed Code -->
<script>
window.hsConversationsSettings = {
loadImmediately: false,
inlineEmbedSelector: '#hubspot-conversations-inline-embed-selector',
};
</script>
<script type="text/javascript" id="hs-script-loader" async defer src="//js-na1.hs-scripts.com/your-portal-id-here.js"></script>
<!-- End of HubSpot Embed Code -->


This is the provider: HubspotConversationsProvider.tsx

import { createStyles } from '@mantine/core';
import React, {
createContext,
FC,
useCallback,
useContext,
useEffect,
useState,
} from 'react';
import ReactDOM from 'react-dom';
import { useLocation } from 'react-router-dom';

interface HubspotConversationsContextType {
toggleWidget: () => void;
isOpen: boolean;
unreadMessagesCount: number;
}

const HubspotConversationsContext =
createContext<HubspotConversationsContextType | null>(null);

const HUBSPOT_INLINE_EMBED_ELEMENT_ID =
'hubspot-conversations-inline-embed-selector';

export const HubspotConversationsProvider: FC = ({ children }) => {
const location = useLocation();

const [isReady, setIsReady] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const [unreadMessagesCount, setUnreadMessagesCount] = useState(0);

const { classes } = useStyles(isOpen);

const user = useCurrentUser();
// This is for Visitor Identification API
const hubspotToken = useHubspotConversationsToken();

const hideWidget = useCallback(() => {
setIsOpen(false);
}, []);

const showWidget = useCallback(() => {
if (!isReady) return;

window.HubSpotConversations.widget.load();
window.HubSpotConversations.widget.open();

setIsOpen(true);
}, [isReady]);

const toggleWidget = useCallback(() => {
if (isOpen) {
hideWidget();
} else {
showWidget();
}
}, [hideWidget, isOpen, showWidget]);

const onConversationsReady = useCallback(() => {
setIsReady(true);
}, []);

useEffect(
function init() {
if (window.HubSpotConversations) {
onConversationsReady();
} else {
window.hsConversationsOnReady = [onConversationsReady];
}
},
[onConversationsReady]
);

useEffect(
function updateSettingsAndLoadWidget() {
if (hubspotToken.isFetched && hubspotToken?.data) {
window.hsConversationsSettings = {
...window.hsConversationsSettings,
identificationEmail: user?.email,
identificationToken: hubspotToken.data.token,
};
window.HubSpotConversations.widget.load();
}
},
[hubspotToken.data, hubspotToken.isFetched, user?.email]
);

useEffect(
function addEventListeners() {
if (!isReady) return;

function listener(payload: { unreadCount: number }) {
setUnreadMessagesCount(payload.unreadCount);
}

window.HubSpotConversations.on(
'unreadConversationCountChanged',
listener
);

return () => {
window.HubSpotConversations.off(
'unreadConversationCountChanged',
listener
);
};
},
[isReady]
);

useEffect(
function refreshConversationsOnRouteChange() {
if (!isReady) return;

window.HubSpotConversations.widget.refresh();
},
[isReady]
);

return (
<HubspotConversationsContext.Provider
value={{ isOpen, toggleWidget, unreadMessagesCount }}
>
{children}

{ReactDOM.createPortal(
<div
className={classes.chatWidgetContainer}
id={HUBSPOT_INLINE_EMBED_ELEMENT_ID}
/>,
document.body
)}
</HubspotConversationsContext.Provider>
);
};

const useStyles = createStyles((theme, isOpen: boolean) => ({
chatWidgetContainer: {
overflow: 'hidden',
zIndex: 2147483647, // this is the max possible value
position: 'fixed',
top: 75,
right: theme.spacing.xl,
height: 500,
width: 376,
display: isOpen ? 'block' : 'none',
borderRadius: theme.radius.md,
backgroundColor: theme.white,
boxShadow: '0 5px 20px rgb(0 0 0 / 10%)',

'#hubspot-conversations-inline-parent': {
width: '100%',
height: '100%',
},

'#hubspot-conversations-inline-iframe': {
width: '100%',
height: '100%',
border: 'none',
},
},
}));

export function useHubspotConversations() {
const context = useContext(HubspotConversationsContext);

if (context === null) {
throw new Error(
'useHubspotConversations must be used within HubspotConversationsProvider'
);
}

return context;
}

declare global {
interface Window {
hsConversationsSettings: Record<string, any>;
hsConversationsOnReady: Array<() => void>;
HubSpotConversations: {
on: any;
off: any;
widget: {
status: () => { loaded: boolean; pending: boolean };
load: (params?: { widgetOpen: boolean }) => void;
remove: () => void;
open: () => void;
close: () => void;
refresh: (openToNewThread?: boolean) => void;
};
};
}
}

 

And the usage can be something like that:

function App() {
return (
<HubspotConversationsProvider>
<ChatWidgetButton />
</HubspotConversationsProvider>
);
}

function ChatWidgetButton() {
const { toggleWidget } = useHubspotConversations();

return <button onClick={toggleWidget}>Toggle chat</button>;
}

 

0 いいね!
JIanniciello
メンバー

Embed Chat Into A ReactJS SPA

解決

Jquery question here: 
Does anyone know if it is possible to embed a chatbot into a web app written in Jquery? Thanks!

0 いいね!
DA3
参加者

Embed Chat Into A ReactJS SPA

解決
class App extends Component {

    componentDidMount() {

        const script = document.createElement("script");

        script.src="//js.hs-scripts.com/{}.js";
        script.async = true;

        document.body.appendChild(script);

    }

    render() {

        return (
            <>
                <AppLayout/>
                <Cookiebar/>
            </>
        );
    }
}
Mark_Ryba
投稿者 | Elite Partner
投稿者 | Elite Partner

Embed Chat Into A ReactJS SPA

解決

It should work, but it may depend on how you're handling routing. Basically the way the chat function works is you add the standard HS scripts and then configure (in HubSpot) where and when the live chat should pop up. Basically the script needs to be available for the whole app, and then the triggers are handled on HubSpot's side instead of in your codebase. I'm not aware of an NPM or webpack-friendly method of bundling that script, however. I've always done it manually.

 

There may be a conflict between React versions since HubSpot uses React for a lot of their on-page tools. That shouldn't happen, but it is something I've run into in the past. React Dev Tools might help diagnose if there's something like that going on.

kierana
投稿者

Embed Chat Into A ReactJS SPA

解決

I guess if you're using React Router - or some other router you can simply invoke window.HubSpotConversations.widget.refresh(); which apparently re-runs the page matching logic based on the current URL.

kierana
解決策
投稿者

Embed Chat Into A ReactJS SPA

解決

Something like this should work:

 

// Create a hook to seperate out logic.
const useHubspotChat = (portalId) => { const [ hasLoaded, setHasLoaded ] = React.useState(false); const [ activeConversation, setActiveConversation ] = React.useState(false); const eventRef = React.useRef(null); React.useEffect(() => { console.log('hey') // Add event listener. window.hsConversationsOnReady = [() => { setHasLoaded(true); }]; // Create script component. let script = document.createElement('script'); script.src=`//js.hs-scripts.com/${portalId}.js`; script.async = true; document.body.appendChild(script); return () => { document.body.removeChild(script); window.hsConversationsOnReady = []; } }, []); // Subscripe to conversation events. React.useEffect(() => { eventRef.current = (payload) => { setActiveConversation(payload.conversation.conversationId); } if (hasLoaded) { window.HubSpotConversations.on( 'conversationStarted', eventRef.current); } return () => { window.HubSpotConversations.off('conversationStarted', eventRef.current); } }, [hasLoaded]); const openHandler = React.useCallback(() => { if (hasLoaded) { window.HubSpotConversations.widget.open(); } }, [hasLoaded]); const closeHandler = React.useCallback(() => { if (hasLoaded) { window.HubSpotConversations.widget.close(); } }, [hasLoaded]) return { hasLoaded, activeConversation, openHandler, closeHandler }; } const App = () => { const { hasLoaded, activeConversation, openHandler, closeHandler } = useHubspotChat(<portalidhere>); return ( <div> hi {hasLoaded ? 'yes': 'no'} conversation: { activeConversation } <button onClick={openHandler}>click me to open</button> <button onClick={closeHandler}>click me to close</button> </div>) } const rootElement = document.getElementById("root"); ReactDOM.render(<App />, rootElement);

 

RScotten
参加者

Embed Chat Into A ReactJS SPA

解決

Learning about this was super helpful:

window.HubSpotConversations.widget...

 

lscanlan
元HubSpot社員
元HubSpot社員

Embed Chat Into A ReactJS SPA

解決

Hi @amjadg,

 

I haven't done this myself but I've been doing some searching around our forums. Here's an example from a while back where someone added the tracking code to a React app: https://community.hubspot.com/t5/APIs-Integrations/Tracking-code-for-a-single-page-application-made-.... If you look at the bottom response there, the user built a page listener component. Maybe that would help with what you're trying to do?

 

I also found this: https://community.hubspot.com/t5/CMS-Development/Chat-integration-issue-with-React/m-p/275219 while doing a search, but I see you've already tried posting to that thread. Maybe we can get @Rajesh16 's attention here, and see if they've made any progress.

 

Also, maybe bumping this thread back to the top will get some more eyes on it.

Leland Scanlan

HubSpot Developer Support
0 いいね!
PaulRBerg
投稿者

Embed Chat Into A ReactJS SPA

解決

Any updates on this?

I tried these methods:

1. Add the script in "index.html"
2. Append the script to the "body" element in a "useEffect" Hook defined in the top-level "App" component

None worked (with React 16.11.0). Unfortunately, this is a showstopper, forcing me to go find another live chat product.

<body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <script src="https://js.hs-scripts.com/MY_ID.js" async></script>
</body>
React.useEffect(() => {
  (function loadHubSpot() {
    const d = document;
    const s = d.createElement("script");

    s.src="https://js.hs-scripts.com/MY_ID.js";
    s.async = true;
    d.getElementsByTagName("body")[0].appendChild(s);
  })();
}, [])

 

0 いいね!
anitaernszt
メンバー

Embed Chat Into A ReactJS SPA

解決

Try adding <script .... /> to the <head></head> component instead of <body></body>

I've added to index.html this way and it's working for me

slowtokyo
参加者

Embed Chat Into A ReactJS SPA

解決

This worked for me as well.

padecaluwe
メンバー

Embed Chat Into A ReactJS SPA

解決

we have the same problem here, nothing worked

0 いいね!
alexlisong
メンバー

Embed Chat Into A ReactJS SPA

解決

Have same issue here, any updates?

0 いいね!