Skip to content

Commit 9a1b104

Browse files
Add Adobe Dynamic Chat Provider
1 parent 8051760 commit 9a1b104

12 files changed

Lines changed: 308 additions & 2 deletions

File tree

README.md

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
An npm module that allows you to mitigate the negative performance and user
99
experience impact of chat tools. `react-live-chat-loader` shows a fake widget
10-
until the page has become idle or users are ready to interact with chat. Currently works with [Intercom](#intercom), [Help Scout](#help-scout), [Drift](#drift), [Messenger](#messenger), [Userlike](#userlike), [Front](#front), [Chatwoot](#chatwoot) and [Hubspot](#hubspot).
10+
until the page has become idle or users are ready to interact with chat. Currently works with [Intercom](#intercom), [Help Scout](#help-scout), [Drift](#drift), [Messenger](#messenger), [Userlike](#userlike), [Front](#front), [Chatwoot](#chatwoot), [Hubspot](#hubspot) and [Adobe Dynamic Chat](#adobe-dynamic-chat)
1111

1212
Made by the team at [♠ Calibre](https://calibreapp.com/), your performance companion.
1313

@@ -417,6 +417,46 @@ You can customise the Hubspot placeholder by passing the following props to the
417417

418418
</details>
419419

420+
<details>
421+
<summary id="adobe-dynamic-chat">Adobe Dynamic Chat</summary>
422+
423+
To use Adobe Dynamic Chat import the `LiveChatLoaderProvider` and set the `provider` prop
424+
as `adobeDynamicChat` and the props for your instance as found in your Chatbot settings > Installation > Javascript snippet.
425+
426+
For example, your script URL will look something like this:
427+
`<script src="https://assets.adoberesources.net/loader.js?orgId=ABCD1234ABCD1234ABCD123%40AdobeOrg&instanceId=yourinstance&env=prod&geo=va7"></script>`
428+
429+
Then import the `AdobeDynamicChat` component.
430+
431+
```jsx
432+
import { LiveChatLoaderProvider, AdobeDynamicChat } from 'react-live-chat-loader'
433+
434+
export default class App extends React.Component {
435+
render() {
436+
return (
437+
<LiveChatLoaderProvider
438+
providerKey="ABCD1234ABCD1234ABCD123%40AdobeOrg" // Use "orgId" query parameter found in script URL
439+
instanceId="yourinstance" // Use "instanceId" query parameter found in script URL
440+
env="prod" // Use "env" query parameter found in script URL
441+
geo="va7" // Use "geo" query parameter found in script URL
442+
provider="adobeDynamicChat"
443+
>
444+
/* ... */
445+
<AdobeDynamicChat />
446+
</LiveChatLoaderProvider>
447+
)
448+
}
449+
}
450+
```
451+
452+
You can customise the Adobe Dynamic Chat placeholder icon by passing the following props to the `AdobeDynamicChat` component:
453+
454+
- `color`: The background color of the placeholder widget
455+
- `containerClass`: Class to be added to the placeholder element, defaults to `live-chat-loader-placeholder`
456+
- `icon`: Override the default Adobe Dynamic Chat icon, can be any JSX element.
457+
458+
</details>
459+
420460
## ➕ Adding a Provider
421461

422462
To add a new live chat provider, follow the steps in [Contributing: Adding a Provider](CONTRIBUTING.md#-adding-a-provider).
@@ -464,6 +504,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
464504
<td align="center"><a href="https://github.com/lauGutierrezz"><img src="https://avatars.githubusercontent.com/u/52488696?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Laura Gutiérrez López de la Franca</b></sub></a><br /><a href="https://github.com/calibreapp/react-live-chat-loader/commits?author=lauGutierrezz" title="Code">💻</a></td>
465505
<td align="center"><a href="https://github.com/38ri581oq480"><img src="https://avatars.githubusercontent.com/u/64654807?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kirill Vakalov</b></sub></a><br /><a href="https://github.com/calibreapp/react-live-chat-loader/commits?author=38ri581oq480" title="Code">💻</a></td>
466506
<td align="center"><a href="http://luisrudge.net"><img src="https://avatars.githubusercontent.com/u/941075?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Luís Rudge</b></sub></a><br /><a href="https://github.com/calibreapp/react-live-chat-loader/commits?author=luisrudge" title="Code">💻</a></td>
507+
<td align="center"><a href="https://github.com/enjoyjeremy-bc"><img src="https://avatars.githubusercontent.com/u/260613?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jeremy Adam</b></sub></a><br /><a href="https://github.com/calibreapp/react-live-chat-loader/commits?author=enjoyjeremy-bc" title="Code">💻</a></td>
467508
</tr>
468509
</table>
469510

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
"chatwoot",
3030
"userlike",
3131
"facebook messenger",
32-
"messenger"
32+
"messenger",
33+
"adobe dynamic chat"
3334
],
3435
"author": "calibreapp.com",
3536
"license": "MIT",
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import React, { useState, useEffect, CSSProperties, ReactElement } from 'react'
2+
3+
import useChat from '../../hooks/useChat'
4+
import useWindowWidth from '../../hooks/useWindowWidth'
5+
import { ProviderProps, ClassNames } from '../../types'
6+
7+
const styles: {
8+
container: CSSProperties
9+
button: CSSProperties
10+
icon: CSSProperties
11+
iconWrapper: CSSProperties
12+
} = {
13+
container: {
14+
WebkitFontSmoothing: 'antialiased',
15+
fontSize: 16,
16+
display: 'flex',
17+
alignItems: 'flex-end',
18+
padding: '12px',
19+
flexDirection: 'column'
20+
},
21+
button: {
22+
textAlign: 'center',
23+
display: 'flex',
24+
justifyContent: 'center',
25+
alignItems: 'center',
26+
fill: '#fff',
27+
cursor: 'pointer',
28+
height: '56px',
29+
width: '56px',
30+
borderRadius: '.3125rem',
31+
boxShadow: '0 2px 6px 0 rgba(0,0,0,.4)',
32+
overflow: 'hidden',
33+
outline: 'none',
34+
border: 'none'
35+
},
36+
icon: {
37+
display: 'flex',
38+
alignItems: 'center',
39+
justifyContent: 'center',
40+
position: 'absolute',
41+
top: '0',
42+
left: '0',
43+
width: '48px',
44+
height: '48px',
45+
transition: 'transform 100ms linear, opacity 80ms linear'
46+
},
47+
iconWrapper: {
48+
fill: 'inherit',
49+
stroke: 'inherit',
50+
width: '100%',
51+
padding: 0,
52+
lineHeight: 0
53+
}
54+
}
55+
56+
interface Props extends ProviderProps {
57+
color?: string
58+
icon?: ReactElement
59+
}
60+
61+
const AdobeDynamicChat = ({
62+
color = '#0265dc',
63+
icon: Icon,
64+
containerClass = ClassNames.container
65+
}: Props): JSX.Element | null => {
66+
const [state, loadChat] = useChat({ loadWhenIdle: true })
67+
const windowWidth = useWindowWidth()
68+
const [positionStyles, setPositionStyles] = useState<CSSProperties>({
69+
zIndex: 100,
70+
position: 'fixed',
71+
display: 'block'
72+
})
73+
74+
useEffect(() => {
75+
setPositionStyles(state => ({
76+
...state,
77+
bottom: windowWidth < 768 ? 0 : '48px',
78+
right: windowWidth < 768 ? 0 : '48px'
79+
}))
80+
}, [windowWidth])
81+
82+
if (state === 'complete') {
83+
return null
84+
}
85+
86+
return (
87+
<div className={containerClass} style={positionStyles}>
88+
<div style={styles.container}>
89+
<div
90+
role="button"
91+
aria-label="Load Chat"
92+
aria-busy="true"
93+
aria-live="polite"
94+
onClick={() => loadChat({ open: true })}
95+
onMouseEnter={() => loadChat({ open: false })}
96+
style={{
97+
backgroundColor: color,
98+
...styles.icon,
99+
...styles.button
100+
}}
101+
>
102+
{Icon || (
103+
<svg
104+
focusable="false"
105+
width="36"
106+
height="36"
107+
viewBox="0 0 36 36"
108+
fill="none"
109+
aria-hidden="true"
110+
role="img"
111+
xmlns="http://www.w3.org/2000/svg"
112+
>
113+
<g>
114+
<path
115+
fill="#ffffff"
116+
d="M32.667 14h-1.334A1.335 1.335 0 0030 15.337v-1.8a5.508 5.508 0 00-5.508-5.508h-4.283L20.222 8l-1.59-5.477a.643.643 0 00-1.264 0L15.778 8l.01.031h-4.28A5.508 5.508 0 006 13.539v1.8A1.335 1.335 0 004.667 14H3.333A1.335 1.335 0 002 15.337v7.325A1.336 1.336 0 003.333 24h1.334A1.336 1.336 0 006 22.662v1.83A5.508 5.508 0 0011.508 30h12.984A5.508 5.508 0 0030 24.492v-1.83A1.336 1.336 0 0031.333 24h1.334A1.336 1.336 0 0034 22.662v-7.325A1.335 1.335 0 0032.667 14zM10 17a3 3 0 113 3 3 3 0 01-3-3zm12 8.49a.5.5 0 01-.5.5h-7a.5.5 0 01-.5-.5v-1a.5.5 0 01.5-.5h7a.5.5 0 01.5.5zM23 20a3 3 0 113-3 3 3 0 01-3 3z"
117+
></path>
118+
<circle fill="#ffffff" cx="13" cy="17" r="1.5"></circle>
119+
<circle fill="#ffffff" cx="23" cy="17" r="1.5"></circle>
120+
</g>
121+
</svg>
122+
)}
123+
</div>
124+
</div>
125+
</div>
126+
)
127+
}
128+
129+
export default AdobeDynamicChat

src/components/LiveChatLoaderProvider.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ interface LiveChatLoaderProps {
1212
baseUrl?: string
1313
// locale is only relevant to certain providers, e.g. Messenger and Chatwoot
1414
locale?: string
15+
// instanceId, env and geo are only relevant for Adobe Dynamic Chat
16+
instanceId?: string
17+
env?: string
18+
geo?: string
1519
beforeInit?: () => void
1620
onReady?: () => void
1721
}

src/context.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ interface Context {
1111
locale?: string
1212
idlePeriod?: number
1313
baseUrl?: string
14+
// instanceId, env and geo are only relevant for Adobe Dynamic Chat
15+
instanceId?: string
16+
env?: string
17+
geo?: string
1418
beforeInit?: () => void
1519
onReady?: () => void
1620
}

src/hooks/useChat.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ const useChat = (
2828
appID,
2929
locale,
3030
baseUrl,
31+
// instanceId, env and geo are only relevant for Adobe Dynamic Chat
32+
instanceId,
33+
env,
34+
geo,
3135
beforeInit,
3236
onReady
3337
} = useContext(LiveChatLoaderContext)
@@ -92,6 +96,9 @@ const useChat = (
9296
appID,
9397
locale,
9498
baseUrl,
99+
instanceId,
100+
env,
101+
geo,
95102
beforeInit,
96103
onReady
97104
})

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ export { default as Userlike } from './components/Userlike'
88
export { default as Chatwoot } from './components/Chatwoot'
99
export { default as Front } from './components/Front'
1010
export { default as HubSpot } from './components/HubSpot'
11+
export { default as AdobeDynamicChat } from './components/AdobeDynamicChat'
1112
export { default as LiveChatLoaderProvider } from './components/LiveChatLoaderProvider'

src/providers/adobeDynamicChat.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { State } from '../types'
2+
import waitForLoad from '../utils/waitForLoad'
3+
4+
const domain = 'https://assets.adoberesources.net'
5+
6+
declare global {
7+
interface Window {
8+
//eslint-disable-next-line @typescript-eslint/no-explicit-any
9+
AdobeDX: any
10+
}
11+
}
12+
13+
/* eslint-disable */
14+
const loadScript = (srcUrl: string): boolean => {
15+
if (window.AdobeDX) return false
16+
;(function(d, t) {
17+
var script: HTMLScriptElement = d.createElement('script')
18+
var firstScript = d.getElementsByTagName('script')[0]
19+
script.src = srcUrl
20+
firstScript.parentNode?.insertBefore(script, firstScript)
21+
})(document)
22+
return true
23+
}
24+
/* eslint-enable */
25+
26+
const load = ({
27+
setState,
28+
baseUrl = domain,
29+
providerKey,
30+
instanceId,
31+
env,
32+
geo,
33+
beforeInit = () => undefined,
34+
onReady = () => undefined
35+
}: {
36+
setState: (state: State) => void
37+
baseUrl?: string
38+
providerKey?: string
39+
instanceId?: string
40+
env?: string
41+
geo?: string
42+
beforeInit?: () => void
43+
onReady?: () => void
44+
}): void => {
45+
const srcUrl = `${baseUrl}/loader.js?orgId=${providerKey}&instanceId=${instanceId}&env=${env}&&geo=${geo}`
46+
const loaded = loadScript(srcUrl)
47+
48+
// Continue as long as Adobe hasn’t already been initialised.
49+
if (loaded) {
50+
beforeInit()
51+
waitForLoad(
52+
() => window.AdobeDX,
53+
// Allow Adobe to complete loading before removing fake widget
54+
() =>
55+
setTimeout(() => {
56+
setState('complete')
57+
onReady()
58+
}, 2000)
59+
)
60+
}
61+
}
62+
63+
const open = (): void =>
64+
window.addEventListener('adobedx.conversations.ready', () => {
65+
// There is no way to open the chat programmatically
66+
});
67+
68+
export default {
69+
domain,
70+
load,
71+
open
72+
}

src/providers/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ export { default as userlike } from './userlike'
66
export { default as front } from './front'
77
export { default as chatwoot } from './chatwoot'
88
export { default as hubSpot } from './hubSpot'
9+
export { default as adobeDynamicChat } from './adobeDynamicChat'

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ export type Provider =
1616
| 'chatwoot'
1717
| 'front'
1818
| 'hubSpot'
19+
| 'adobeDynamicChat'

0 commit comments

Comments
 (0)