Skip to content

Commit db36b2f

Browse files
committed
add support for HubSpot
1 parent e009510 commit db36b2f

5 files changed

Lines changed: 247 additions & 0 deletions

File tree

src/components/HubSpot/index.tsx

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import React, {
2+
ReactElement,
3+
useState
4+
} from 'react'
5+
import useChat from '../../hooks/useChat'
6+
const Icon = () => (
7+
<svg
8+
xmlns="http://www.w3.org/2000/svg"
9+
xmlnsXlink="http://www.w3.org/1999/xlink"
10+
width="32"
11+
height="30"
12+
viewBox="0 0 39 37"
13+
className="conversations-visitor-open-icon"
14+
>
15+
<defs>
16+
<path
17+
id="conversations-visitor-open-icon-path-10.8870447034539481"
18+
d="M31.4824242 24.6256121L31.4824242 0.501369697 0.476266667 0.501369697 0.476266667 24.6256121z"
19+
></path>
20+
</defs>
21+
<g fill="none" fillRule="evenodd" stroke="none" strokeWidth="1">
22+
<g transform="translate(-1432 -977) translate(1415.723 959.455)">
23+
<g transform="translate(17 17)">
24+
<g transform="translate(6.333 .075)">
25+
<path
26+
fill="#ffffff"
27+
d="M30.594 4.773c-.314-1.943-1.486-3.113-3.374-3.38C27.174 1.382 22.576.5 15.36.5c-7.214 0-11.812.882-11.843.889-1.477.21-2.507.967-3.042 2.192a83.103 83.103 0 019.312-.503c6.994 0 11.647.804 12.33.93 3.079.462 5.22 2.598 5.738 5.728.224 1.02.932 4.606.932 8.887 0 2.292-.206 4.395-.428 6.002 1.22-.516 1.988-1.55 2.23-3.044.008-.037.893-3.814.893-8.415 0-4.6-.885-8.377-.89-8.394"
28+
></path>
29+
</g>
30+
<g fill="#ffffff" transform="translate(0 5.832)">
31+
<path d="M31.354 4.473c-.314-1.944-1.487-3.114-3.374-3.382-.046-.01-4.644-.89-11.859-.89-7.214 0-11.813.88-11.843.888-1.903.27-3.075 1.44-3.384 3.363C.884 4.489 0 8.266 0 12.867c0 4.6.884 8.377.889 8.393.314 1.944 1.486 3.114 3.374 3.382.037.007 3.02.578 7.933.801l2.928 5.072a1.151 1.151 0 001.994 0l2.929-5.071c4.913-.224 7.893-.794 7.918-.8 1.902-.27 3.075-1.44 3.384-3.363.01-.037.893-3.814.893-8.414 0-4.601-.884-8.378-.888-8.394"></path>
32+
</g>
33+
</g>
34+
</g>
35+
</g>
36+
</svg>
37+
)
38+
39+
const HubSpot = ({
40+
backgroundColor,
41+
loader: Loader
42+
}: {
43+
backgroundColor?: string
44+
loader?: ReactElement
45+
}): JSX.Element | null => {
46+
const [state, loadChat] = useChat({ loadWhenIdle: false })
47+
const [isLoading, setIsLoading] = useState(false)
48+
if (state === 'complete') {
49+
return null
50+
}
51+
return (
52+
<div
53+
style={{
54+
zIndex: 1051, // 1 more than the actual widget
55+
paddingBottom: '16px',
56+
position: 'fixed',
57+
bottom: 0,
58+
paddingLeft: '0px',
59+
paddingRight: '16px',
60+
left: 'inherit',
61+
right: '0px'
62+
}}
63+
>
64+
<span
65+
style={{
66+
display: 'flex !important',
67+
paddingLeft: '24px !important',
68+
paddingTop: '20px !important',
69+
float: 'right'
70+
}}
71+
>
72+
<div
73+
style={{
74+
position: 'relative',
75+
display: 'inline-flex',
76+
alignItems: 'baseline',
77+
lineHeight: 1
78+
}}
79+
>
80+
<button
81+
onClick={() => {
82+
setIsLoading(true);
83+
loadChat({ open: true });
84+
}}
85+
aria-label="Open live chat"
86+
aria-haspopup="false"
87+
style={{
88+
fontWeight: 400,
89+
fontSize: '14px',
90+
color: 'rgb(51, 71, 91)',
91+
backgroundColor: backgroundColor || 'rgb(66, 91, 118)',
92+
boxShadow:
93+
'rgba(0, 0, 0, 0.1) 0px 1px 6px, rgba(0, 0, 0, 0.2) 0px 2px 24px',
94+
border: 'medium none',
95+
transition: 'box-shadow 150ms ease-in-out 0s',
96+
position: 'relative',
97+
borderRadius: '50%',
98+
height: '60px',
99+
width: '60px'
100+
}}
101+
>
102+
<div
103+
style={{
104+
position: 'absolute',
105+
top: '50%',
106+
left: '50%',
107+
transform: 'translate(-50%, -50%)',
108+
display: 'flex',
109+
width: '32px',
110+
height: '30px',
111+
lineHeight: 1
112+
}}
113+
>
114+
{isLoading && Loader ? Loader : <Icon />}
115+
</div>
116+
</button>
117+
</div>
118+
</span>
119+
</div>
120+
)
121+
}
122+
123+
export default HubSpot

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ export { default as Intercom } from './components/Intercom'
66
export { default as Messenger } from './components/Messenger'
77
export { default as Userlike } from './components/Userlike'
88
export { default as Chatwoot } from './components/Chatwoot'
9+
export { default as HubSpot } from './components/HubSpot'
910
export { default as LiveChatLoaderProvider } from './components/LiveChatLoaderProvider'

src/providers/hubSpot.ts

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import { State } from '../types'
2+
import waitForLoad from '../utils/waitForLoad'
3+
4+
export const domain = 'js.hs-scripts.com'
5+
declare global {
6+
interface Window {
7+
//eslint-disable-next-line @typescript-eslint/no-explicit-any
8+
HubSpotConversations: any
9+
//eslint-disable-next-line @typescript-eslint/no-explicit-any
10+
hsConversationsSettings: any
11+
//eslint-disable-next-line @typescript-eslint/no-explicit-any
12+
hsConversationsOnReady: any
13+
}
14+
}
15+
16+
const loadScript = (hsId: string) => {
17+
// Detect the provider is already loaded and return early
18+
console.debug({ loadScript: window.HubSpotConversations })
19+
if (window.HubSpotConversations) {
20+
return false
21+
}
22+
(function loadHubSpotSDK(d, s, id) {
23+
// fetch customerchat.js
24+
const fjs = d.getElementsByTagName(s)[0]
25+
if (d.getElementById(id)) {
26+
return
27+
}
28+
//eslint-disable-next-line @typescript-eslint/no-explicit-any
29+
const js = d.createElement(s) as any
30+
js.id = id
31+
js.src = `https://${domain}/${hsId}.js`
32+
js.type = 'text/javascript'
33+
js.async = 1
34+
js.defer = 1
35+
if (fjs) {
36+
fjs.parentNode?.insertBefore(js, fjs)
37+
} else {
38+
d.body.appendChild(js)
39+
}
40+
})(window.document, 'script', 'hs-script-loader')
41+
42+
return true
43+
}
44+
45+
const load = ({
46+
providerKey,
47+
setState,
48+
beforeInit = () => undefined,
49+
onReady = () => undefined,
50+
}: {
51+
providerKey: string
52+
setState: (state: State) => void
53+
beforeInit?: () => void
54+
onReady?: () => void
55+
}): boolean => {
56+
window.hsConversationsOnReady = [
57+
() => {
58+
window.HubSpotConversations.widget.load()
59+
console.debug({
60+
hsConversationsOnReady: 'ready',
61+
widgetStatus: window.HubSpotConversations.widget.status()
62+
})
63+
}
64+
]
65+
const loaded = loadScript(providerKey)
66+
if (loaded) {
67+
beforeInit()
68+
69+
waitForLoad(
70+
() => {
71+
console.debug({
72+
waitForLoad: {
73+
HubSpotConversations: window.HubSpotConversations,
74+
widget: window.HubSpotConversations?.widget
75+
}
76+
})
77+
return Boolean(
78+
window.HubSpotConversations &&
79+
window.HubSpotConversations.widget &&
80+
window.HubSpotConversations.widget.status().loaded
81+
)
82+
},
83+
// Allow intercom to complete loading before removing fake widget
84+
() => {
85+
console.debug({
86+
loadComplete: window.HubSpotConversations,
87+
widgetStatus: window.HubSpotConversations.widget.status()
88+
})
89+
window.HubSpotConversations.widget.open()
90+
setState('complete')
91+
onReady()
92+
console.debug({
93+
widgetStatusAfterTimeout: window.HubSpotConversations.widget.status()
94+
})
95+
}
96+
)
97+
}
98+
return loaded
99+
}
100+
101+
const open = (): unknown => {
102+
console.debug({ open: 'called' })
103+
window.HubSpotConversations &&
104+
window.HubSpotConversations.widget &&
105+
!window.HubSpotConversations.widget.status().loaded &&
106+
window.HubSpotConversations.widget.load()
107+
108+
return (
109+
window.HubSpotConversations &&
110+
window.HubSpotConversations.widget &&
111+
window.HubSpotConversations.widget.open()
112+
)
113+
} // Open provider
114+
const close = (): unknown => window.HubSpotConversations.widget.close() // Close provider
115+
116+
export default {
117+
load,
118+
open,
119+
close,
120+
domain
121+
}

src/providers/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ export { default as intercom } from './intercom'
44
export { default as messenger } from './messenger'
55
export { default as userlike } from './userlike'
66
export { default as chatwoot} from './chatwoot'
7+
export {default as hubSpot} from './hubSpot'

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ export type Provider =
77
| 'drift'
88
| 'userlike'
99
| 'chatwoot'
10+
| 'hubSpot'

0 commit comments

Comments
 (0)