/
useChat.ts
108 lines (90 loc) · 3.03 KB
/
useChat.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import { useContext, useCallback, useEffect } from 'react'
import { State } from 'types'
import { LiveChatLoaderContext } from 'context'
import Providers from 'providers'
const requestIdleCallback =
typeof window !== 'undefined' ? window.requestIdleCallback : null
const connection =
typeof window !== 'undefined'
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
window.navigator && (window.navigator as any).connection
: null
let scriptLoaded = false
const useChat = (
{
loadWhenIdle
}: {
loadWhenIdle: boolean
} = { loadWhenIdle: false }
): [State, ({ open }: { open: boolean }) => void] => {
const {
provider,
providerKey,
idlePeriod,
state,
setState,
appID,
locale
} = useContext(LiveChatLoaderContext)
useEffect(() => {
// Don't load if idlePeriod is 0, null or undefined
if (typeof window === 'undefined' || !loadWhenIdle || !idlePeriod) return
// Don't load if 2g connection or save-data is enabled
if (
connection &&
(connection.saveData || /2g/.test(connection.effectiveType))
)
return
if (isNaN(idlePeriod)) return
// deadline.timeRemaining() has an upper limit of 50 milliseconds
// We want to ensure the page has been idle for a significant period of time
// Therefore we count consecutive maximum timeRemaining counts and load chat when we reach our threshold
let elapsedIdlePeriod = 0
let previousTimeRemaining = 0
const scheduleLoadChat = (deadline: IdleDeadline) => {
if (elapsedIdlePeriod > idlePeriod) return loadChat({ open: false })
const timeRemaining = deadline.timeRemaining()
// To ensure browser is idle, only accumalte elapsedIdlePeriod when
// two consecutive maximum timeRemaining's have been observed
if (previousTimeRemaining > 49 && timeRemaining > 49)
elapsedIdlePeriod += timeRemaining
previousTimeRemaining = timeRemaining
requestIdleCallback?.(scheduleLoadChat)
}
if (requestIdleCallback) {
requestIdleCallback(scheduleLoadChat)
} else {
setTimeout(() => loadChat({ open: false }), idlePeriod)
}
}, [])
const chatProvider = Providers[provider]
const loadChat = useCallback<(args: { open: boolean }) => void>(
({ open = true }) => {
if (!providerKey) {
//eslint-disable-next-line no-console
console.error('No api key given to react-live-chat-loader')
return
}
if (!provider) {
//eslint-disable-next-line no-console
console.error('No provider given to react-live-chat-loader')
return
}
if (state === 'opening') return
if (state === 'open') return chatProvider.close()
if (state === 'complete') return chatProvider.open()
if (!scriptLoaded) {
scriptLoaded = true
chatProvider.load({ providerKey, setState, appID, locale })
}
if (open) {
setState('opening')
chatProvider.open()
setState('open')
}
},
[]
)
return [state, loadChat]
}
export default useChat