Skip to content

Commit 8003539

Browse files
author
Michael Dijkstra
authored
Merge pull request #94 from myleslinder/feat/lifecycle-callbacks
Add callbacks for before chat provider init and after script ready
2 parents a8f46ca + c96863c commit 8003539

10 files changed

Lines changed: 97 additions & 25 deletions

File tree

README.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
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-8-orange.svg?style=flat-square)](#contributors-)
6+
57
<!-- ALL-CONTRIBUTORS-BADGE:END -->
68

7-
[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.0-4baaaa.svg)](CODE_OF_CONDUCT.md)
9+
[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.0-4baaaa.svg)](CODE_OF_CONDUCT.md)
810

911
An npm module that allows you to mitigate the negative performance and user
1012
experience impact of chat tools. `react-live-chat-loader` shows a fake widget
@@ -22,7 +24,7 @@ Made by the team at [♠ Calibre](https://calibreapp.com/), your performance com
2224
6. [Contributing](#-contributing)
2325
7. [Examples](#-examples)
2426

25-
## 💡 How it Works
27+
## 💡 How it Works
2628

2729
Chat widgets rely heavily on JavaScript which comes at a cost. Given the
2830
significant impact that comes from the download, parse, compile and execution of
@@ -40,7 +42,7 @@ connection (using `navigator.connection.effectiveType`) or has data-saver enable
4042

4143
> ⚠️ **Please note**: Some chat widget providers open automatically based on the people’s interaction from their last session.
4244
43-
## 📥 Installation
45+
## 📥 Installation
4446

4547
To download react-live-chat-loader run:
4648

@@ -126,6 +128,8 @@ You can pass the following props to the `LiveChatLoaderProvider` provider:
126128
- `idlePeriod`: How long to wait in ms before loading the provider. Default is
127129
`2000`. Set to `0` to never load. This value is used in a `setTimeout` in
128130
browsers that don't support `requestIdleCallback`.
131+
- `beforeInit`: A function to be called after the script has loaded, but before the chat provider has been initialized (optional)
132+
- `onReady`: A function to be called once the script has been loaded, the chat provider has been initialized and is ready for use (optional)
129133

130134
## 💬 Supported Providers
131135

@@ -338,9 +342,11 @@ You can customise the Chatwoot Widget by passing the following props to the
338342
</details>
339343

340344
## ➕ Adding a Provider
345+
341346
To add a new live chat provider, follow the steps in [Contributing: Adding a Provider](CONTRIBUTING.md#-adding-a-provider).
342347

343348
## 🙌 Contributing
349+
344350
Happy to hear you’re interested in contributing to React Live Chat Loader! Please find our contribution guidelines [here](CONTRIBUTING.md).
345351

346352
## 🖥️ Examples
@@ -352,7 +358,7 @@ Happy to hear you’re interested in contributing to React Live Chat Loader! Ple
352358
- [How to avoid performance regressions when using live chat tools](https://calibreapp.com/blog/fast-live-chat)
353359
- [Reducing the Intercom Messenger bundle size by 65%](https://www.intercom.com/blog/reducing-intercom-messenger-bundle-size/)
354360

355-
## ✨ Contributors
361+
## ✨ Contributors
356362

357363
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
358364

src/components/LiveChatLoaderProvider.tsx

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,24 @@ import * as Providers from '../providers'
33
import { State, Provider } from '../types'
44
import { LiveChatLoaderContext } from '../context'
55

6-
export const LiveChatLoaderProvider = ({
7-
provider,
8-
children,
9-
idlePeriod = 5000,
10-
baseUrl,
11-
...props
12-
}: {
6+
interface LiveChatLoaderProps {
137
provider: Provider
148
children: JSX.Element
159
idlePeriod?: number
1610
providerKey: string
1711
appID?: string
1812
baseUrl?: string
19-
}): JSX.Element | null => {
13+
beforeInit?: () => void
14+
onReady?: () => void
15+
}
16+
17+
export const LiveChatLoaderProvider = ({
18+
provider,
19+
children,
20+
idlePeriod = 5000,
21+
baseUrl,
22+
...props
23+
}: LiveChatLoaderProps): JSX.Element | null => {
2024
const [state, setState] = useState<State>('initial')
2125
const value = {
2226
provider,

src/context.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ interface Context {
1111
locale?: string
1212
idlePeriod?: number
1313
baseUrl?: string
14+
beforeInit?: () => void
15+
onReady?: () => void
1416
}
1517

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

src/hooks/useChat.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ const useChat = (
2727
setState,
2828
appID,
2929
locale,
30-
baseUrl
30+
baseUrl,
31+
beforeInit,
32+
onReady
3133
} = useContext(LiveChatLoaderContext)
3234

3335
useEffect(() => {
@@ -84,7 +86,15 @@ const useChat = (
8486
return
8587
}
8688

87-
chatProvider.load({ providerKey, setState, appID, locale, baseUrl })
89+
chatProvider.load({
90+
providerKey,
91+
setState,
92+
appID,
93+
locale,
94+
baseUrl,
95+
beforeInit,
96+
onReady
97+
})
8898

8999
if (open) {
90100
chatProvider.open()

src/providers/chatwoot.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,25 @@ const load = ({
3939
providerKey,
4040
locale = 'en',
4141
setState,
42-
baseUrl = domain
42+
baseUrl = domain,
43+
beforeInit = () => undefined,
44+
onReady = () => undefined
4345
}: {
4446
providerKey: string
4547
locale?: string
4648
setState: (state: State) => void
4749
baseUrl?: string
50+
beforeInit?: () => void
51+
onReady?: () => void
4852
}): void => {
4953
const loaded = loadScript(function() {
50-
setTimeout(() => setState('complete'), 1000)
54+
beforeInit()
55+
56+
setTimeout(() => {
57+
setState('complete')
58+
onReady()
59+
}, 1000)
60+
5161
window.chatwootSDK.run({
5262
websiteToken: providerKey,
5363
baseUrl,

src/providers/drift.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,19 +69,25 @@ const loadScript = (): boolean => {
6969

7070
const load = ({
7171
providerKey,
72-
setState
72+
setState,
73+
beforeInit = () => undefined,
74+
onReady = () => undefined
7375
}: {
7476
providerKey: string
7577
setState: (state: State) => void
78+
beforeInit?: () => void
79+
onReady?: () => void
7680
}): boolean => {
7781
const loaded = loadScript()
7882

7983
// Continue as long as drift hasn’t already been initialised.
8084
if (loaded) {
85+
beforeInit()
8186
window.drift.load(providerKey)
8287
window.drift.SNIPPET_VERSION = '0.3.1'
8388
window.drift.on('ready', () => {
8489
setState('complete')
90+
onReady()
8591
})
8692
}
8793

src/providers/helpScout.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,27 @@ const loadScript = (): boolean => {
3939

4040
const load = ({
4141
providerKey,
42-
setState
42+
setState,
43+
beforeInit = () => undefined,
44+
onReady = () => undefined
4345
}: {
4446
providerKey: string
4547
setState: (state: State) => void
48+
beforeInit?: () => void
49+
onReady?: () => void
4650
}): boolean => {
4751
const loaded = loadScript()
4852

4953
// Continue as long as helpscout hasn’t already been initialised.
5054
if (loaded) {
55+
beforeInit()
5156
window.Beacon('init', providerKey)
5257
window.Beacon('once', 'ready', () =>
5358
// Allow helpscout to complete loading before removing fake widget
54-
setTimeout(() => setState('complete'), 2000)
59+
setTimeout(() => {
60+
setState('complete')
61+
onReady()
62+
}, 2000)
5563
)
5664
}
5765

src/providers/intercom.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,29 @@ const loadScript = (appId: string): boolean => {
4747

4848
const load = ({
4949
providerKey,
50-
setState
50+
setState,
51+
beforeInit = () => undefined,
52+
onReady = () => undefined
5153
}: {
5254
providerKey: string
5355
setState: (state: State) => void
56+
beforeInit?: () => void
57+
onReady?: () => void
5458
}): boolean => {
5559
const loaded = loadScript(providerKey)
5660

5761
// Continue as long as userlike hasn’t already been initialised.
5862
if (loaded) {
63+
beforeInit()
5964
window.Intercom('boot', { app_id: providerKey })
6065
waitForLoad(
6166
() => window.Intercom.booted,
6267
// Allow intercom to complete loading before removing fake widget
63-
() => setTimeout(() => setState('complete'), 2000)
68+
() =>
69+
setTimeout(() => {
70+
setState('complete')
71+
onReady()
72+
}, 2000)
6473
)
6574
}
6675

src/providers/messenger.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,20 @@ const loadScript = (locale: string): boolean => {
3636
const load = ({
3737
appID,
3838
locale = 'en_US',
39-
setState
39+
setState,
40+
beforeInit = () => undefined,
41+
onReady = () => undefined
4042
}: {
4143
appID?: string
4244
locale?: string
4345
setState: (state: State) => void
46+
beforeInit?: () => void
47+
onReady?: () => void
4448
}): boolean => {
4549
const loaded = loadScript(locale)
4650
// Continue as long as messenger hasn’t already been initialised.
4751
if (loaded) {
52+
beforeInit()
4853
window.fbAsyncInit = function() {
4954
window.FB.init(
5055
Object.assign(
@@ -58,7 +63,10 @@ const load = ({
5863
)
5964
window.FB.Event.subscribe('customerchat.load', () =>
6065
// Allow messenger to complete loading before removing fake widget
61-
setTimeout(() => setState('complete'), 3000)
66+
setTimeout(() => {
67+
setState('complete')
68+
onReady()
69+
}, 3000)
6270
)
6371
}
6472
}

src/providers/userlike.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,27 @@ const loadScript = (providerKey: string): boolean => {
3535

3636
const load = ({
3737
providerKey,
38-
setState
38+
setState,
39+
beforeInit = () => undefined,
40+
onReady = () => undefined
3941
}: {
4042
providerKey: string
4143
setState: (state: State) => void
44+
beforeInit?: () => void
45+
onReady?: () => void
4246
}): boolean => {
4347
const loaded = loadScript(providerKey)
4448
// Continue as long as userlike hasn’t already been initialised.
4549
if (loaded) {
50+
beforeInit()
4651
waitForLoad(
4752
() => !!window.userlike,
4853
// Allow userlike to complete loading before removing fake widget
49-
() => setTimeout(() => setState('complete'), 2000)
54+
() =>
55+
setTimeout(() => {
56+
setState('complete')
57+
onReady()
58+
}, 2000)
5059
)
5160
}
5261

0 commit comments

Comments
 (0)