Skip to content

Commit 27c97e0

Browse files
author
Michael Dijkstra
authored
Merge pull request #72 from motiko/chatwoot
Chatwoot
2 parents 13316a1 + c8b7dde commit 27c97e0

11 files changed

Lines changed: 206 additions & 4 deletions

File tree

README.md

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
# React Live Chat Loader
22

33
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
4+
45
[![All Contributors](https://img.shields.io/badge/all_contributors-6-orange.svg?style=flat-square)](#contributors-)
6+
57
<!-- ALL-CONTRIBUTORS-BADGE:END -->
68

79
An npm module that allows you to mitigate the negative performance and user
@@ -126,7 +128,7 @@ You can pass the following props to the `LiveChatLoaderProvider` provider:
126128

127129
## Supported Providers
128130

129-
Currently there are five supported providers:
131+
Currently there are six supported providers:
130132

131133
<details>
132134
<summary>Help Scout</summary>
@@ -305,6 +307,35 @@ You can customise the Userlike Widget by passing the following props to the
305307

306308
</details>
307309

310+
<details>
311+
<summary> Chatwoot </summary>
312+
313+
To use Chatwoot import the `LiveChatLoaderProvider` and set the `provider` prop
314+
as `chatwoot` and the `providerKey` prop as your Chatwoot secret.
315+
316+
Then import the `Chatwoot` component.
317+
318+
```jsx
319+
import { LiveChatLoaderProvider, Chatwoot } from 'react-live-chat-loader'
320+
321+
export default () => (
322+
<LiveChatLoaderProvider
323+
providerKey="E33wn9ftxMDHZx18AaBkfPvY"
324+
provider="chatwoot"
325+
>
326+
/* ... */
327+
<Chatwoot />
328+
</LiveChatLoaderProvider>
329+
)
330+
```
331+
332+
You can customise the Chatwoot Widget by passing the following props to the
333+
`Chatwoot` component:
334+
335+
- `color`: The background color, set to same color value you choose in Chatwoot dashboard.
336+
337+
</details>
338+
308339
## Adding a provider
309340

310341
To contribute a new provider, follow these steps:

src/components/Chatwoot/index.tsx

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import useChat from 'hooks/useChat'
2+
import React, { CSSProperties } from 'react'
3+
4+
const styles: {
5+
button: CSSProperties
6+
img: CSSProperties
7+
} = {
8+
button: {
9+
borderRadius: '100px',
10+
bottom: '20px',
11+
right: '20px',
12+
boxShadow: '0 8px 24px rgb(0 0 0 / 16%)',
13+
cursor: 'pointer',
14+
height: '64px',
15+
position: 'fixed',
16+
width: '64px',
17+
zIndex: 2147483001,
18+
userSelect: 'none'
19+
},
20+
img: {
21+
height: '24px',
22+
margin: '20px',
23+
width: '24px'
24+
}
25+
}
26+
27+
interface Props {
28+
color?: string
29+
}
30+
31+
const Provider = ({ color }: Props): JSX.Element | null => {
32+
const [state, loadChat] = useChat({ loadWhenIdle: true })
33+
34+
if (state === 'complete') return null
35+
36+
return (
37+
<div>
38+
<div
39+
onClick={() => loadChat({ open: true })}
40+
onMouseEnter={() => loadChat({ open: false })}
41+
style={{
42+
...styles.button,
43+
backgroundColor: color
44+
}}
45+
>
46+
<img
47+
style={styles.img}
48+
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAAUVBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////8IN+deAAAAGnRSTlMAAwgJEBk0TVheY2R5eo+ut8jb5OXs8fX2+cjRDTIAAADsSURBVHgBldZbkoMgFIThRgQv8SKKgGf/C51UnJqaRI30/9zfe+NQUQ3TvG7bOk9DVeCmshmj/CuOTYnrdBfkUOg0zlOtl9OWVuEk4+QyZ3DIevmSt/ioTvK1VH/s5bY3YdM9SBZ/mUUyWgx+U06ycgp7D8msxSvtc4HXL9BLdj2elSEfhBJAI0QNgJEBI1BEBsQClVBVGDgwYOLAhJkDM1YOrNg4sLFAsLJgZsHEgoEFFQt0JAFGFjQsKAMJ0LFAexKgZYFyJIDxJIBNJEDNAtSJBLCeBDCOBFAPzwFA94ED+zmhwDO9358r8ANtIsMXi7qVAwAAAABJRU5ErkJggg=="
49+
alt="bubble-icon"
50+
/>
51+
</div>
52+
</div>
53+
)
54+
}
55+
56+
Provider.defaultProps = {
57+
color: '#1f93ff'
58+
}
59+
60+
export default Provider

src/components/LiveChatLoaderProvider.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,23 @@ export const LiveChatLoaderProvider = ({
77
provider,
88
children,
99
idlePeriod = 5000,
10+
baseUrl,
1011
...props
1112
}: {
1213
provider: Provider
1314
children: JSX.Element
1415
idlePeriod?: number
1516
providerKey: string
1617
appID?: string
18+
baseUrl?: string
1719
}): JSX.Element | null => {
1820
const [state, setState] = useState<State>('initial')
1921
const value = {
2022
provider,
2123
idlePeriod,
2224
state,
2325
setState,
26+
baseUrl,
2427
...props
2528
}
2629

@@ -36,7 +39,11 @@ export const LiveChatLoaderProvider = ({
3639

3740
return (
3841
<LiveChatLoaderContext.Provider value={value}>
39-
<link href={chatProvider.domain} rel="preconnect" crossOrigin="" />
42+
<link
43+
href={baseUrl || chatProvider.domain}
44+
rel="preconnect"
45+
crossOrigin=""
46+
/>
4047
{children}
4148
</LiveChatLoaderContext.Provider>
4249
)

src/context.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ interface Context {
99
appID?: string
1010
locale?: string
1111
idlePeriod?: number
12+
baseUrl?: string
1213
}
1314

1415
export const LiveChatLoaderContext = createContext<Context>({} as Context)

src/hooks/useChat.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ const useChat = (
2727
state,
2828
setState,
2929
appID,
30-
locale
30+
locale,
31+
baseUrl
3132
} = useContext(LiveChatLoaderContext)
3233

3334
useEffect(() => {
@@ -90,7 +91,7 @@ const useChat = (
9091

9192
if (!scriptLoaded) {
9293
scriptLoaded = true
93-
chatProvider.load({ providerKey, setState, appID, locale })
94+
chatProvider.load({ providerKey, setState, appID, locale, baseUrl })
9495
}
9596

9697
if (open) {

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { default as HelpScout } from './components/HelpScout'
55
import { default as Intercom } from './components/Intercom'
66
import { default as Messenger } from './components/Messenger'
77
import { default as Userlike } from './components/Userlike'
8+
import { default as Chatwoot} from './components/Chatwoot'
89
import { default as LiveChatLoaderProvider } from './components/LiveChatLoaderProvider'
910

1011
export {
@@ -15,5 +16,6 @@ export {
1516
Intercom,
1617
Messenger,
1718
Userlike,
19+
Chatwoot,
1820
LiveChatLoaderProvider
1921
}

src/providers/chatwoot.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { State } from 'types'
2+
3+
const domain = 'https://app.chatwoot.com'
4+
5+
declare global {
6+
interface Window {
7+
//eslint-disable-next-line @typescript-eslint/no-explicit-any
8+
chatwootSettings: any
9+
//eslint-disable-next-line @typescript-eslint/no-explicit-any
10+
$chatwoot: any
11+
chatwootSDK: {
12+
run: (options: {
13+
websiteToken: string
14+
baseUrl: string
15+
locale?: string
16+
type?: 'standard' | 'expanded_bubble'
17+
position?: 'left' | 'right'
18+
}) => void
19+
}
20+
}
21+
}
22+
23+
/* eslint-disable */
24+
const loadScript = (onload: () => void, baseUrl: string): void => {
25+
if (window.$chatwoot) return
26+
;(function(d, t) {
27+
var script: HTMLScriptElement = d.createElement('script')
28+
var fisrtScript = d.getElementsByTagName('script')[0]
29+
script.src = baseUrl + '/packs/js/sdk.js'
30+
fisrtScript.parentNode?.insertBefore(script, fisrtScript)
31+
script.onload = onload
32+
})(document)
33+
}
34+
/* eslint-enable */
35+
36+
const load = ({
37+
providerKey,
38+
locale = 'en',
39+
setState,
40+
baseUrl = domain
41+
}: {
42+
providerKey: string
43+
locale?: string
44+
setState: (state: State) => void
45+
baseUrl?: string
46+
}): void => {
47+
loadScript(function() {
48+
setTimeout(() => setState('complete'), 1000)
49+
window.chatwootSDK.run({
50+
websiteToken: providerKey,
51+
baseUrl,
52+
locale
53+
})
54+
}, baseUrl)
55+
}
56+
57+
const open = (): void => window.$chatwoot && window.$chatwoot.toggle()
58+
59+
const close = (): void => window.$chatwoot && window.$chatwoot.toggle()
60+
61+
export default {
62+
domain,
63+
load,
64+
open,
65+
close
66+
}

src/providers/index.ts

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

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ export type Provider =
66
| 'messenger'
77
| 'drift'
88
| 'userlike'
9+
| 'chatwoot'

website/pages/chatwoot.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from 'react'
2+
import Layout from '../layouts/main'
3+
import ExampleLinks from '../components/exampleLinks'
4+
import { LiveChatLoaderProvider, Chatwoot } from 'react-live-chat-loader'
5+
6+
const Page = () => (
7+
<LiveChatLoaderProvider provider="chatwoot" providerKey="E33wn9ftxMDHZx18AaBkfPvY">
8+
<Layout title="React Live Chat Loader: Chatwoot">
9+
<div className="wrapper">
10+
<div className="inner">
11+
<h1>React Live Chat Loader: Chatwoot</h1>
12+
<p>
13+
This is an example implementation of the Chatwoot widget using{' '}
14+
<a href="https://github.com/calibreapp/react-live-chat-loader">
15+
react-live-chat-loader
16+
</a>
17+
.
18+
</p>
19+
<ExampleLinks />
20+
</div>
21+
</div>
22+
<Chatwoot />
23+
</Layout>
24+
</LiveChatLoaderProvider>
25+
)
26+
27+
export default Page

0 commit comments

Comments
 (0)