@microsoft/omnichannel-chat-sdk 1.1.1-main.4abcbae → 1.1.1-main.8727062

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,22 +1,59 @@
1
- # Omnichannel Chat SDK
1
+ # Omnichannel Chat SDK 💬
2
2
 
3
3
  [![npm version](https://badge.fury.io/js/%40microsoft%2Fomnichannel-chat-sdk.svg)](https://badge.fury.io/js/%40microsoft%2Fomnichannel-chat-sdk)
4
4
  [![install size](https://packagephobia.com/badge?p=@microsoft/omnichannel-chat-sdk)](https://packagephobia.com/result?p=@microsoft/omnichannel-chat-sdk)
5
5
  ![Release CI](https://github.com/microsoft/omnichannel-chat-sdk/workflows/Release%20CI/badge.svg)
6
6
  ![npm](https://img.shields.io/npm/dm/@microsoft/omnichannel-chat-sdk)
7
7
 
8
+ > ❗ Chat SDK **v1.1.0** is the minimum version to support the **new** messaging platform. More [here](https://docs.microsoft.com/en-us/dynamics365/customer-service/migrate-acs)
9
+
10
+ > 📢 Try out our new React component library [omnichannel-chat-widget](https://github.com/microsoft/omnichannel-chat-widget) with Chat SDK
11
+
8
12
  Headless Chat SDK to build your own chat widget against Dynamics 365 Omnichannel Services.
9
13
 
10
- Please make sure you have a chat widget configured before using this package or you can follow this [link](https://docs.microsoft.com/en-us/dynamics365/customer-service/configure-live-chat)
14
+ Please make sure you have a chat widget configured before using this package or you can follow this [link](https://docs.microsoft.com/en-us/dynamics365/customer-service/add-chat-widget)
11
15
 
12
16
  ## Table of Contents
13
17
  - [Live Chat Widget vs. Chat SDK](#live-chat-widget-vs-chat-sdk)
14
18
  - [Installation](#installation)
15
19
  - [Installation on React Native](#installation-on-react-native)
16
- - [API Reference](#api-reference)
17
- - [API Examples](#api-examples)
18
- - [Sample Apps](https://github.com/microsoft/omnichannel-chat-sdk-samples)
20
+ - [SDK Methods](#sdk-methods)
21
+ - [Initialization](#initialization)
22
+ - [Start Chat](#start-chat)
23
+ - [End Chat](#end-chat)
24
+ - [Get Pre-Chat Survey](#get-pre-chat-survey)
25
+ - [Get Live Chat Config](#get-live-chat-config)
26
+ - [Get Current Live Chat Context](#get-current-live-chat-context)
27
+ - [Get Data Masking Rules](#get-data-masking-rules)
28
+ - [Get Chat Reconnect Context](#get-chat-reconnect-context)
29
+ - [Get Conversation Details](#get-conversation-details)
30
+ - [Get Chat Token](#get-chat-token)
31
+ - [Get Calling Token](#get-calling-token)
32
+ - [Get Messages](#get-messages)
33
+ - [Send Messages](#send-messages)
34
+ - [On New Message](#on-new-message)
35
+ - [On Typing Event](#on-typing-event)
36
+ - [On Agent End Session](#on-agent-end-session)
37
+ - [Send Typing Event](#send-typing-event)
38
+ - [Email Live Chat Transcript](#email-live-chat-transcript)
39
+ - [Get Live Chat Transcript](#get-live-chat-transcript)
40
+ - [Upload File Attachment](#upload-file-attachment)
41
+ - [Download File Attachment](#download-file-attachment)
42
+ - [Create Chat Adapter](#create-chat-adapter)
43
+ - [Get Voice & Video Calling](#get-voice--video-calling)
44
+ - [Get Post Chat Survey Context](#get-post-chat-survey-context)
19
45
  - [Common Scenarios](#common-scenarios)
46
+ - [Using BotFramework-WebChat](#using-botframework-webchat)
47
+ - [Escalation to Voice & Video](#escalation-to-voice--video)
48
+ - [Pre-Chat Survey](#pre-chat-survey)
49
+ - [Post-Chat Survey](#post-chat-survey)
50
+ - [Reconnect to existing Chat](#reconnect-to-existing-chat)
51
+ - [Authenticated Chat](#authenticated-chat)
52
+ - [Persistent Chat](#persistent-chat)
53
+ - [Chat Reconnect with Authenticated User](#chat-reconnect-with-authenticated-user)
54
+ - [Chat Reconnect with Unauthenticated User](#chat-reconnect-with-unauthenticated-user)
55
+ - [Operating Hours](#operating-hours)
56
+ - [Sample Apps](https://github.com/microsoft/omnichannel-chat-sdk-samples)
20
57
  - [Feature Comparisons](#feature-comparisons)
21
58
  - [Telemetry](#telemetry)
22
59
  - [Development Guide](docs/DEVELOPMENT_GUIDE.md)
@@ -60,7 +97,7 @@ Omnichannel offers an live chat widget (LCW) by default. You can use the Chat SD
60
97
  ## Installation
61
98
 
62
99
  ```
63
- npm install @microsoft/omnichannel-chat-sdk --save
100
+ npm install @microsoft/omnichannel-chat-sdk --save
64
101
  ```
65
102
 
66
103
  ## Installation on React Native
@@ -108,243 +145,302 @@ The following steps will be required to run Omnichannel Chat SDK on React Native
108
145
  import 'react-native-url-polyfill';
109
146
  ```
110
147
 
111
- ## API Reference
112
-
113
- | Method | Description | Notes |
114
- | ------ | ----------- | ----- |
115
- | OmnichannelChatSDK.initialize() | Initializes ChatSDK internal data | |
116
- | OmnichannelChatSDK.startChat() | Starts OC chat, handles prechat response | |
117
- | OmnichannelChatSDK.endChat() | Ends OC chat | |
118
- | OmnichannelChatSDK.getPreChatSurvey() | Adaptive card data of PreChat survey | |
119
- | OmnichannelChatSDK.getLiveChatConfig() | Get live chat config | |
120
- | OmnichannelChatSDK.getDataMaskingRules() | Get active data masking rules | |
121
- | OmnichannelChatSDK.getCurrentLiveChatContext() | Get current live chat context information to reconnect to the same chat | |
122
- | OmnichannelChatSDK.getChatReconnectContext() | Get current reconnectable chat context information to reconnect to a previous existing chat session | |
123
- | OmnichannelChatSDK.getConversationDetails() | Get details of the current conversation such as its state & when the agent joined the conversation | |
124
- | OmnichannelChatSDK.getChatToken() | Get chat token | |
125
- | OmnichannelChatSDK.getCallingToken() | Get calling token | |
126
- | OmnichannelChatSDK.getMessages() | Get all messages | |
127
- | OmnichannelChatSDK.sendMessage() | Send message | |
128
- | OmnichannelChatSDK.onNewMessage() | Handles system message, client/agent messages, adaptive cards, attachments to download | |
129
- | OmnichannelChatSDK.onTypingEvent() | Handles agent typing event | |
130
- | OmnichannelChatSDK.onAgentEndSession() | Handler when agent ends session | |
131
- | OmnichannelChatSDK.sendTypingEvent() | Sends customer typing event | |
132
- | OmnichannelChatSDK.emailLiveChatTranscript() | Email transcript | |
133
- | OmnichannelChatSDK.getLiveChatTranscript() | Get transcript data (JSON) | |
134
- | OmnichannelChatSDK.uploadFileAttachment() | Send file attachment | |
135
- | OmnichannelChatSDK.downloadFileAttachment() | Download file attachment | |
136
- | OmnichannelChatSDK.createChatAdapter() | Get Chat Adapter | **Web only** |
137
- | OmnichannelChatSDK.getVoiceVideoCalling() | Get VoiceVideoCall SDK for Escalation to Voice & Video | **Web only** |
138
- | OmnichannelChatSDK.getPostChatSurveyContext() | Get post chat survey link, survey locale, and whether an agent has joined the survey | |
139
-
140
- ## API examples
141
-
142
- ### Import
143
- ```ts
144
- import OmnichannelChatSDK from '@microsoft/omnichannel-chat-sdk';
145
- ```
148
+ ## SDK Methods
146
149
 
147
150
  ### Initialization
151
+
152
+ It handles the initialization of ChatSDK internal data.
153
+
148
154
  ```ts
149
- const omnichannelConfig = {
150
- orgUrl: "",
151
- orgId: "",
152
- widgetId: ""
153
- };
155
+ import OmnichannelChatSDK from '@microsoft/omnichannel-chat-sdk';
154
156
 
155
- const chatSDKConfig = { // Optional
156
- dataMasking: {
157
- disable: false,
158
- maskingCharacter: '#'
159
- }
160
- };
157
+ const omnichannelConfig = {
158
+ orgUrl: "",
159
+ orgId: "",
160
+ widgetId: ""
161
+ };
161
162
 
162
- const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
163
- await chatSDK.initialize();
164
- ```
163
+ const chatSDKConfig = { // Optional
164
+ dataMasking: {
165
+ disable: false,
166
+ maskingCharacter: '#'
167
+ }
168
+ };
165
169
 
166
- ### Get Current Live Chat Context
167
- ```ts
168
- const liveChatContext = await chatSDK.getCurrentLiveChatContext();
170
+ const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
171
+ await chatSDK.initialize();
169
172
  ```
170
173
 
171
- ### Get Current Chat Reconnect Context
174
+ ### Start Chat
175
+
176
+ It starts an Omnichannel conversation.
177
+
172
178
  ```ts
173
- const optionalParams = {
174
- reconnectId: '', // reconnect Id
175
- };
179
+ const customContext = {
180
+ 'contextKey1': {'value': 'contextValue1', 'isDisplayable': true},
181
+ 'contextKey2': {'value': 12.34, 'isDisplayable': false},
182
+ 'contextKey3': {'value': true}
183
+ };
176
184
 
177
- const chatReconnectContext = await chatSDK.getChatReconnectContext(optionalParams);
185
+ const optionalParams = {
186
+ preChatResponse: '', // PreChatSurvey response
187
+ liveChatContext: {}, // EXISTING chat context data
188
+ customContext, // Custom Context
189
+ sendDefaultInitContext: true // Send default init context ⚠️ Web only
190
+ };
191
+
192
+ await chatSDK.startChat(optionalParams);
178
193
  ```
179
194
 
180
- ### Get Conversation Details
195
+ ### End Chat
196
+
197
+ It ends the current Omnichannel conversation.
198
+
181
199
  ```ts
182
- const conversationDetails = await chatSDK.getConversationDetails();
200
+ await chatSDK.endChat();
183
201
  ```
184
202
 
185
- ### Get Chat Token
203
+ ### Get Pre-Chat Survey
204
+
205
+ It gets the Pre-Chat Survey from Live Chat Config. Pre-Chat Survey is in Adaptive Card format.
206
+
207
+ `Option 1`
186
208
  ```ts
187
- const chatToken = await chatSDK.getChatToken();
209
+ const preChatSurvey = await getPreChatSurvey(); // Adaptive Cards JSON payload data
188
210
  ```
189
-
190
- ### Get Calling Token
211
+ `Option 2`
191
212
  ```ts
192
- const callingToken = await chatSDK.getCallingToken();
213
+ const parseToJSON = false;
214
+ const preChatSurvey = await getPreChatSurvey(parseToJSON); // Adaptive Cards payload data as string
193
215
  ```
194
216
 
195
217
  ### Get Live Chat Config
218
+
219
+ It fetches the Live Chat Config.
220
+
196
221
  ```ts
197
- const liveChatConfig = await chatSDK.getLiveChatConfig();
222
+ const liveChatConfig = await chatSDK.getLiveChatConfig();
198
223
  ```
199
224
 
200
- ### Get Data Masking Rules
225
+ ### Get Current Live Chat Context
226
+
227
+ It gets the current live chat context information to be used to reconnect to the same conversation.
228
+
201
229
  ```ts
202
- const dataMaskingRules = await chatSDK.getDataMaskingRules();
230
+ const liveChatContext = await chatSDK.getCurrentLiveChatContext();
203
231
  ```
204
232
 
205
- ### Get PreChat Survey
206
- `Option 1`
233
+ ### Get Data Masking Rules
234
+
235
+ It gets the active data masking rules from Live Chat Config.
236
+
207
237
  ```ts
208
- const preChatSurvey = await getPreChatSurvey(); // Adaptive Cards JSON payload data
238
+ const dataMaskingRules = await chatSDK.getDataMaskingRules();
209
239
  ```
210
- `Option 2`
240
+
241
+ ### Get Chat Reconnect Context
242
+
243
+ It gets the current reconnectable chat context information to connect to a previous existing chat session.
244
+
245
+ `Reconnection options` is required. See [documentation](https://docs.microsoft.com/en-us/dynamics365/customer-service/configure-reconnect-chat?tabs=customerserviceadmincenter#enable-reconnection-to-a-previous-chat-session)
246
+
211
247
  ```ts
212
- const parseToJSON = false;
213
- const preChatSurvey = await getPreChatSurvey(parseToJSON); // Adaptive Cards payload data as string
248
+ const optionalParams = {
249
+ reconnectId: '', // reconnect Id
250
+ };
251
+
252
+ const chatReconnectContext = await chatSDK.getChatReconnectContext(optionalParams);
214
253
  ```
215
254
 
216
- ### Get PostChat Survey
255
+ ### Get Conversation Details
256
+
257
+ It gets the details of the current conversation such as its state & when the agent joined the conversation.
258
+
217
259
  ```ts
218
- try {
219
- const context = await chatSDK.getPostChatSurveyContext();
220
- if (context.participantJoined) { // participantJoined will be true if an agent has joined the conversation, or a bot has joined the conversation and the bot survey flag has been turned on on the admin side.
221
- // formsProLocale is the default language you have set on the CustomerVoice portal. You can override this url parameter with any locale that CustomerVoice supports.
222
- // If "&lang=" is not set on the url, the locale will be English.
223
- const linkToSend = context.surveyInviteLink + "&lang=" + context.formsProLocale;
224
- // This link is accessible and will redirect to the survey page. Use it as you see fit.
225
- }
226
- } catch (ex) {
227
- // If the post chat should not be shown by any reason (e.g. post chat is not enabled), promise will be rejected.
228
- }
260
+ const conversationDetails = await chatSDK.getConversationDetails();
229
261
  ```
230
262
 
231
- ### Start Chat
263
+ ### Get chat Token
264
+
265
+ It gets the chat token used to initiates a chat with Omnichannel messaging client.
266
+
232
267
  ```ts
233
- const customContext = {
234
- 'contextKey1': {'value': 'contextValue1', 'isDisplayable': true},
235
- 'contextKey2': {'value': 12.34, 'isDisplayable': false},
236
- 'contextKey3': {'value': true}
237
- };
268
+ const chatToken = await chatSDK.getChatToken();
269
+ ```
238
270
 
239
- const optionalParams = {
240
- preChatResponse: '', // PreChatSurvey response
241
- liveChatContext: {}, // EXISTING chat context data
242
- customContext // Custom Context
243
- };
244
- await chatSDK.startChat(optionalParams);
271
+ ### Get Calling Token
272
+
273
+ It gets the calling token used to initiates a Voice & Video Call.
274
+
275
+ ```ts
276
+ const callingToken = await chatSDK.getCallingToken();
245
277
  ```
246
278
 
247
- ### End Chat
279
+ ### Get Messages
280
+
281
+ It gets all the messages of the current conversation.
282
+
248
283
  ```ts
249
- await chatSDK.endChat();
284
+ const messages = await chatSDK.getMessages();
250
285
  ```
251
286
 
252
- ### On New Message Handler
287
+ ### Send Messages
288
+
289
+ It sends a message to Omnichannel.
290
+
253
291
  ```ts
254
- const optionalParams = {
255
- rehydrate: true, // Rehydrate all previous messages of existing conversation (false by default)
256
- }
292
+ import {DeliveryMode, MessageContentType, MessageType, PersonType} from '@microsoft/omnichannel-chat-sdk';
293
+
294
+ ...
257
295
 
258
- chatSDK.onNewMessage((message) => {
259
- console.log(`[NewMessage] ${message.content}`); // IC3 protocol message data
260
- console.log(message);
261
- }, optionalParams);
296
+ const displayName = "Contoso"
297
+ const message = "Sample message from customer";
298
+ const messageToSend = {
299
+ content: message
300
+ };
301
+
302
+ await chatSDK.sendMessage(messageToSend);
262
303
  ```
263
304
 
264
- ### On Agent End Session
305
+ ### On New Message
306
+
307
+ It subscribes to new incoming messages of the current conversation such as system messages, client messages, agent messages, adaptive cards and attachments.
308
+
265
309
  ```ts
266
- chatSDK.onAgentEndSession(() => {
267
- console.log("Session ended!");
268
- });
269
- ```
310
+ const optionalParams = {
311
+ rehydrate: true, // Rehydrate all previous messages of existing conversation (false by default)
312
+ }
270
313
 
314
+ chatSDK.onNewMessage((message) => {
315
+ console.log(`[NewMessage] ${message.content}`);
316
+ console.log(message);
317
+ }, optionalParams);
318
+ ```
271
319
  ### On Typing Event
320
+
321
+ It subscribes to agent typing event.
322
+
272
323
  ```ts
273
- chatSDK.onTypingEvent(() => {
274
- console.log("Agent is typing...");
275
- })
324
+ chatSDK.onTypingEvent(() => {
325
+ console.log("Agent is typing...");
326
+ })
276
327
  ```
277
328
 
278
- ### Get Messages
329
+ ### On Agent End Session
330
+
331
+ It subscribes to agent ending the session of the conversation.
332
+
279
333
  ```ts
280
- const messages = await chatSDK.getMessages();
334
+ chatSDK.onAgentEndSession(() => {
335
+ console.log("Session ended!");
336
+ });
281
337
  ```
282
338
 
283
- ### Send Message
339
+ ### Send Typing Event
340
+
341
+ It sends a customer typing event.
342
+
284
343
  ```ts
285
- import {DeliveryMode, MessageContentType, MessageType, PersonType} from '@microsoft/omnichannel-chat-sdk';
344
+ await chatSDK.sendTypingEvent();
345
+ ```
286
346
 
287
- ...
347
+ ### Email Live Chat Transcript
288
348
 
289
- const displayName = "Contoso"
290
- const message = "Sample message from customer";
291
- const messageToSend = {
292
- content: message
293
- };
349
+ It sends an email of the live chat transcript.
294
350
 
295
- await chatSDK.sendMessage(messageToSend);
351
+ ```ts
352
+ const body = {
353
+ emailAddress: 'contoso@microsoft.com',
354
+ attachmentMessage: 'Attachment Message'
355
+ };
356
+ await chatSDK.emailLiveChatTranscript(body);
296
357
  ```
297
358
 
298
- ### Send Typing
359
+ ### Get Live Chat Transcript
360
+
361
+ It fetches the current conversation transcript data in JSON.
362
+
299
363
  ```ts
300
- await chatSDK.sendTypingEvent();
364
+ await chatSDK.getLiveChatTranscript();
301
365
  ```
302
366
 
303
- ### Upload Attachment
367
+ ### Upload File Attachment
368
+
369
+ It sends a file attachment to the current conversation.
370
+
304
371
  ```ts
305
- const fileInfo = {
306
- name: '',
307
- type: '',
308
- size: '',
309
- data: ''
310
- };
311
- await chatSDK.uploadFileAttachment(fileInfo);
372
+ const fileInfo = {
373
+ name: '',
374
+ type: '',
375
+ size: '',
376
+ data: ''
377
+ };
378
+ await chatSDK.uploadFileAttachment(fileInfo);
312
379
  ```
313
380
 
314
- ### Download Attachment
381
+ ### Download File Attachment
382
+
383
+ It downloads the file attachment of the incoming message as a Blob response.
384
+
315
385
  ```ts
316
- const blobResponse = await chatsdk.downloadFileAttachment(message.fileMetadata);
386
+ const blobResponse = await chatsdk.downloadFileAttachment(message.fileMetadata);
317
387
 
318
- ...
388
+ ...
319
389
 
320
- // React Native implementation
321
- const fileReaderInstance = new FileReader();
322
- fileReaderInstance.readAsDataURL(blobResponse);
323
- fileReaderInstance.onload = () => {
324
- const base64data = fileReaderInstance.result;
325
- return <Image source={{uri: base64data}}/>
326
- }
390
+ // React Native implementation
391
+ const fileReaderInstance = new FileReader();
392
+ fileReaderInstance.readAsDataURL(blobResponse);
393
+ fileReaderInstance.onload = () => {
394
+ const base64data = fileReaderInstance.result;
395
+ return <Image source={{uri: base64data}}/>
396
+ }
327
397
  ```
328
398
 
329
- ### Get Live Chat Transcript
399
+ ### Create Chat Adapter
400
+
401
+ > :warning: Currently supported on web only
402
+
403
+ It creates a chat adapter to use with [BotFramework-WebChat](https://github.com/microsoft/BotFramework-WebChat).
330
404
 
331
405
  ```ts
332
- await chatSDK.getLiveChatTranscript();
406
+ const chatAdapter = await chatSDK.createChatAdapter();
333
407
  ```
334
408
 
335
- ### Email Live Chat Transcript
409
+ ### Get Voice & Video Calling
410
+
411
+ > :warning: Currently supported on web only
412
+
413
+ It fetches the SDK for Escalation to Voice & Video.
336
414
 
337
415
  ```ts
338
- const body = {
339
- emailAddress: 'contoso@microsoft.com',
340
- attachmentMessage: 'Attachment Message'
341
- };
342
- await chatSDK.emailLiveChatTranscript(body);
416
+ try {
417
+ const VoiceVideoCallingSDK = await chatSDK.getVoiceVideoCalling();
418
+ console.log("VoiceVideoCalling loaded");
419
+ } catch (e) {
420
+ console.log(`Failed to load VoiceVideoCalling: ${e}`);
421
+
422
+ if (e.message === 'UnsupportedPlatform') {
423
+ // Voice Video Calling feature is not supported on this platform
424
+ }
425
+
426
+ if (e.message === 'FeatureDisabled') {
427
+ // Voice Video Calling feature is disabled on admin side
428
+ }
429
+ }
430
+ ```
431
+ ### Get Post Chat Survey Context
432
+
433
+ It gets post chat survey link, survey locale, and whether an agent has joined the survey.
434
+
435
+ ```ts
436
+ const context = await chatSDK.getPostChatSurveyContext();
343
437
  ```
344
438
 
345
439
  ## Common Scenarios
346
440
 
347
- ### PreChatSurvey
441
+ ### Pre-Chat Survey
442
+
443
+ > See https://docs.microsoft.com/en-us/dynamics365/customer-service/configure-pre-chat-survey?tabs=customerserviceadmincenter on how to set up pre-conversation surveys
348
444
 
349
445
  ```ts
350
446
  import * as AdaptiveCards, { Action } from "adaptivecards";
@@ -377,314 +473,359 @@ The following steps will be required to run Omnichannel Chat SDK on React Native
377
473
 
378
474
  ```
379
475
 
476
+ ### Post-Chat Survey
477
+
478
+ > See https://docs.microsoft.com/en-us/dynamics365/customer-service/configure-post-conversation-survey?tabs=customerserviceadmincenter on how to set up post-conversation surveys
479
+
480
+ > ❗ `chatSDK.getPostChatSurveyContext()` needs to be called before `chatSDK.endChat()` is called
481
+
482
+ ```ts
483
+ // 1. Start chat
484
+ await chatSDK.startChat();
485
+
486
+ // 2. Save post chat survey context before ending chat
487
+ try {
488
+ const context = await chatSDK.getPostChatSurveyContext();
489
+ if (context.participantJoined) { // participantJoined will be true if an agent has joined the conversation, or a bot has joined the conversation and the bot survey flag has been turned on on the admin side.
490
+ // formsProLocale is the default language you have set on the CustomerVoice portal. You can override this url parameter with any locale that CustomerVoice supports.
491
+ // If "&lang=" is not set on the url, the locale will be English.
492
+ const linkToSend = context.surveyInviteLink + "&lang=" + context.formsProLocale;
493
+ // This link is accessible and will redirect to the survey page. Use it as you see fit.
494
+ }
495
+ } catch (ex) {
496
+ // If the post chat should not be shown by any reason (e.g. post chat is not enabled), promise will be rejected.
497
+ }
498
+
499
+ // 3. End chat
500
+ await chatSDK.endChat();
501
+
502
+ // 4. Display Post Chat
503
+ ```
504
+
380
505
  ### Reconnect to existing Chat
381
506
 
382
507
  ```ts
383
- await chatSDK.startChat(); // Starts NEW chat
508
+ await chatSDK.startChat(); // Starts NEW chat
384
509
 
385
- const liveChatContext = await chatSDK.getCurrentLiveChatContext(); // Gets chat context
510
+ const liveChatContext = await chatSDK.getCurrentLiveChatContext(); // Gets chat context
386
511
 
387
- cache.saveChatContext(liveChatContext); // Custom logic to save chat context to cache
512
+ cache.saveChatContext(liveChatContext); // Custom logic to save chat context to cache
388
513
 
389
- ...
514
+ ...
390
515
 
391
- // Page/component reloads, ALL previous states are GONE
516
+ // Page/component reloads, ALL previous states are GONE
392
517
 
393
- ...
518
+ ...
394
519
 
395
- const liveChatContext = cache.loadChatContext() // Custom logic to load chat context from cache
520
+ const liveChatContext = cache.loadChatContext() // Custom logic to load chat context from cache
396
521
 
397
- const optionalParams = {};
398
- optionalParams.liveChatContext = liveChatContext;
522
+ const optionalParams = {};
523
+ optionalParams.liveChatContext = liveChatContext;
399
524
 
400
- await chatSDK.startChat(optionalParams); // Reconnects to EXISTING chat
525
+ await chatSDK.startChat(optionalParams); // Reconnects to EXISTING chat
401
526
 
402
- ...
527
+ ...
403
528
 
404
- const messages = await chatSDK.getMessages(); // Gets all messages from EXISTING chat
405
- messages.reverse().forEach((message: any) => renderMessage(message)); // Logic to render all messages to UI
529
+ const messages = await chatSDK.getMessages(); // Gets all messages from EXISTING chat
530
+ messages.reverse().forEach((message: any) => renderMessage(message)); // Logic to render all messages to UI
406
531
  ```
407
532
 
408
533
  ### Authenticated Chat
409
534
 
410
- ```ts
411
- // add if using against an authenticated chat endpoint
412
- // see https://docs.microsoft.com/en-us/dynamics365/omnichannel/administrator/create-chat-auth-settings on how to set up an authenticated chat widget
535
+ > See https://docs.microsoft.com/en-us/dynamics365/customer-service/create-chat-auth-settings?tabs=customerserviceadmincenter#create-a-chat-authentication-setting-record on how to set up an authenticated chat
413
536
 
414
- const chatSDKConfig = {
415
- getAuthToken: async () => {
416
- const response = await fetch("http://contosohelp.com/token");
417
- if (response.ok) {
418
- return await response.text();
419
- }
420
- else {
421
- return null
422
- }
537
+ ```ts
538
+ const chatSDKConfig = {
539
+ getAuthToken: async () => {
540
+ const response = await fetch("http://contosohelp.com/token");
541
+ if (response.ok) {
542
+ return await response.text();
543
+ }
544
+ else {
545
+ return null
423
546
  }
424
547
  }
548
+ }
425
549
 
426
- const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
427
- await chatSDK.initialize();
550
+ const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
551
+ await chatSDK.initialize();
428
552
 
429
- // from this point, this acts like a regular chat widget
553
+ // from this point, this acts like a regular chat widget
430
554
  ```
431
555
 
432
556
  ### Persistent Chat
433
557
 
558
+ > See https://docs.microsoft.com/en-us/dynamics365/customer-service/persistent-chat on how to set up persistent chat
559
+
434
560
  ```ts
435
- const chatSDKConfig = {
436
- persistentChat: {
437
- disable: false,
438
- tokenUpdateTime: 21600000
439
- },
440
- getAuthToken: async () => {
441
- const response = await fetch("http://contosohelp.com/token");
442
- if (response.ok) {
443
- return await response.text();
444
- }
445
- else {
446
- return null
447
- }
561
+ const chatSDKConfig = {
562
+ persistentChat: {
563
+ disable: false,
564
+ tokenUpdateTime: 21600000
565
+ },
566
+ getAuthToken: async () => {
567
+ const response = await fetch("http://contosohelp.com/token");
568
+ if (response.ok) {
569
+ return await response.text();
570
+ }
571
+ else {
572
+ return null
448
573
  }
449
574
  }
575
+ }
450
576
 
451
- const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
452
- await chatSDK.initialize();
577
+ const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
578
+ await chatSDK.initialize();
453
579
 
454
- // from this point, this acts like a persistent chat
580
+ // from this point, this acts like a persistent chat
455
581
  ```
456
582
  ### Chat Reconnect with Authenticated User
457
583
 
584
+ > See https://docs.microsoft.com/en-us/dynamics365/customer-service/configure-reconnect-chat?tabs=customerserviceadmincenter#enable-reconnection-to-a-previous-chat-session on how to set up chat reconnect
585
+
458
586
  ```ts
459
- const chatSDKConfig = {
460
- chatReconnect: {
461
- disable: false,
462
- },
463
- getAuthToken: async () => {
464
- const response = await fetch("http://contosohelp.com/token");
465
- if (response.ok) {
466
- return await response.text();
467
- }
468
- else {
469
- return null
470
- }
587
+ const chatSDKConfig = {
588
+ chatReconnect: {
589
+ disable: false,
590
+ },
591
+ getAuthToken: async () => {
592
+ const response = await fetch("http://contosohelp.com/token");
593
+ if (response.ok) {
594
+ return await response.text();
595
+ }
596
+ else {
597
+ return null
471
598
  }
472
599
  }
600
+ }
473
601
 
474
- const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
475
- await chatSDK.initialize();
602
+ const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
603
+ await chatSDK.initialize();
476
604
 
477
- ...
605
+ ...
478
606
 
479
- const chatReconnectContext = await chatSDK.getChatReconnectContext();
607
+ const chatReconnectContext = await chatSDK.getChatReconnectContext();
480
608
 
481
- if (chatReconnectContext.reconnectId) {
482
- // Add UX with options to reconnect to previous existing chat or start new chat
483
- }
609
+ if (chatReconnectContext.reconnectId) {
610
+ // Add UX with options to reconnect to previous existing chat or start new chat
611
+ }
484
612
 
485
- // Reconnect chat option
486
- const optionalParams = {};
487
- optionalParams.reconnectId = chatReconnectContext.reconnectId;
488
- chatSDK.startChat(optionalParams);
613
+ // Reconnect chat option
614
+ const optionalParams = {};
615
+ optionalParams.reconnectId = chatReconnectContext.reconnectId;
616
+ chatSDK.startChat(optionalParams);
489
617
 
490
- // Start new chat option
491
- chatSDK.startChat();
618
+ // Start new chat option
619
+ chatSDK.startChat();
492
620
  ```
493
621
 
494
622
  ### Chat Reconnect with Unauthenticated User
495
623
 
624
+ > See https://docs.microsoft.com/en-us/dynamics365/customer-service/configure-reconnect-chat?tabs=customerserviceadmincenter#enable-reconnection-to-a-previous-chat-session on how to set up chat reconnect
625
+
496
626
  ```ts
497
- const chatSDKConfig = {
498
- chatReconnect: {
499
- disable: false,
500
- },
501
- }
627
+ const chatSDKConfig = {
628
+ chatReconnect: {
629
+ disable: false,
630
+ },
631
+ }
502
632
 
503
- const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
504
- await chatSDK.initialize();
633
+ const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
634
+ await chatSDK.initialize();
505
635
 
506
- ....
636
+ ....
507
637
 
508
- const optionalParams: any = {};
638
+ const optionalParams: any = {};
509
639
 
510
- // Retrieve reconnect id from the URL
511
- const urlParams = new URLSearchParams(window.location.search);
512
- const reconnectId = urlParams.get('oc.reconnectid');
640
+ // Retrieve reconnect id from the URL
641
+ const urlParams = new URLSearchParams(window.location.search);
642
+ const reconnectId = urlParams.get('oc.reconnectid');
513
643
 
514
- const params = {
515
- reconnectId
516
- };
644
+ const params = {
645
+ reconnectId
646
+ };
517
647
 
518
- // Validate reconnect id
519
- const chatReconnectContext = await chatSDK.getChatReconnectContext(params);
648
+ // Validate reconnect id
649
+ const chatReconnectContext = await chatSDK.getChatReconnectContext(params);
520
650
 
521
- // If the reconnect id is invalid or expired, redirect URL if there is any URL set in the configuration
522
- if (chatReconnectContext.redirectURL) {
523
- window.location.replace(chatReconnectContext.redirectURL);
524
- }
651
+ // If the reconnect id is invalid or expired, redirect URL if there is any URL set in the configuration
652
+ if (chatReconnectContext.redirectURL) {
653
+ window.location.replace(chatReconnectContext.redirectURL);
654
+ }
525
655
 
526
- // Valid reconnect id, reconnect to previous chat
527
- if (chatReconnectContext.reconnectId) {
528
- await chatSDK.startChat({
529
- reconnectId: chatReconnectContext.reconnectId
530
- });
531
- } else { // Reconnect id from URL is not valid, start new chat session
532
- await chatSDK.startChat();
533
- }
656
+ // Valid reconnect id, reconnect to previous chat
657
+ if (chatReconnectContext.reconnectId) {
658
+ await chatSDK.startChat({
659
+ reconnectId: chatReconnectContext.reconnectId
660
+ });
661
+ } else { // Reconnect id from URL is not valid, start new chat session
662
+ await chatSDK.startChat();
663
+ }
534
664
  ```
535
665
 
536
666
  ### Operating Hours
537
667
 
668
+ > See https://docs.microsoft.com/en-us/dynamics365/customer-service/create-operating-hours?tabs=customerserviceadmincenter on how to set up operating hours
669
+
538
670
  ```ts
539
- const chatConfig = await chatSDK.getLiveChatConfig();
540
- const {LiveWSAndLiveChatEngJoin: liveWSAndLiveChatEngJoin} = liveChatConfig;
541
- const {OutOfOperatingHours: outOfOperatingHours} = liveWSAndLiveChatEngJoin;
671
+ const chatConfig = await chatSDK.getLiveChatConfig();
672
+ const {LiveWSAndLiveChatEngJoin: liveWSAndLiveChatEngJoin} = liveChatConfig;
673
+ const {OutOfOperatingHours: outOfOperatingHours} = liveWSAndLiveChatEngJoin;
542
674
 
543
- if (outOfOperatingHours === "True") {
544
- // Handles UX on Out of Operating Hours
545
- } else {
546
- await chatSDK.startChat();
547
- // Renders Custom Chat Widget
548
- }
675
+ if (outOfOperatingHours === "True") {
676
+ // Handles UX on Out of Operating Hours
677
+ } else {
678
+ await chatSDK.startChat();
679
+ // Renders Custom Chat Widget
680
+ }
549
681
  ```
550
682
 
551
- ### Use [BotFramework-WebChat](https://github.com/microsoft/BotFramework-WebChat)
552
-
553
- **NOTE**: Currently supported on web only
554
- ```ts
555
- import OmnichannelChatSDK from '@microsoft/omnichannel-chat-sdk';
556
- import ReactWebChat from 'botframework-webchat';
683
+ ### Using [BotFramework-WebChat](https://github.com/microsoft/BotFramework-WebChat)
684
+ > :warning: Currently supported on web only
557
685
 
558
- ...
686
+ Minimum Requirement Checklist
687
+ 1. [ ] Initialize ChatSDK
688
+ 1. [ ] Start new conversation
689
+ 1. [ ] Create Chat Adapter
690
+ 1. [ ] Create WebChat store with default middlewares
691
+ 1. [ ] Send Default Channel Message Tags using Store Middleware (See [here](/docs//DEVELOPMENT_GUIDE.md#send-default-channel-message-tags-using-store-middleware)) ❗ Required
692
+ 1. [ ] Render WebChat
559
693
 
560
- const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
561
- await chatSDK.initialize();
694
+ ```ts
695
+ import OmnichannelChatSDK from '@microsoft/omnichannel-chat-sdk';
696
+ import ReactWebChat, {createStore} from 'botframework-webchat';
562
697
 
563
- const optionalParams = {
564
- preChatResponse: '' // PreChatSurvey response
565
- };
698
+ // 1. ChatSDK Initialization
699
+ const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig);
700
+ await chatSDK.initialize();
566
701
 
567
- await chatSDK.startChat(optionalParams);
568
- const chatAdapter = await chatSDK.createChatAdapter();
702
+ // 2. Start new conversation
703
+ await chatSDK.startChat();
569
704
 
570
- // Subscribes to incoming message
571
- chatSDK.onNewMessage((message) => {
572
- console.log(`[NewMessage] ${message.content}`); // IC3 protocol message data
573
- console.log(message);
574
- });
705
+ // 3. Create chat adapter
706
+ const chatAdapter = await chatSDK.createChatAdapter();
575
707
 
576
- ...
708
+ // 4. Create WebChat store with middlewares
709
+ const store = createStore(
710
+ {}, // initial state
711
+ sendDefaultMessagingTagsMiddleware // ❗ Required
712
+ );
577
713
 
578
- <ReactWebChat
579
- userID="teamsvisitor"
580
- directLine={chatAdapter}
581
- sendTypingIndicator={true}
582
- />
714
+ // 5. Render WebChat
715
+ <ReactWebChat
716
+ store={store}
717
+ userID="teamsvisitor"
718
+ directLine={chatAdapter}
719
+ sendTypingIndicator={true}
720
+ />
583
721
  ```
584
722
 
585
723
  ### Escalation to Voice & Video
586
- **NOTE**: Currently supported on web only
724
+ > :warning: Currently supported on web only
725
+
726
+ > See https://docs.microsoft.com/en-us/dynamics365/customer-service/call-options-visual-engagement on how to set up calling options
727
+
587
728
  ```ts
588
- import OmnichannelChatSDK from '@microsoft/omnichannel-chat-sdk';
729
+ import OmnichannelChatSDK from '@microsoft/omnichannel-chat-sdk';
589
730
 
590
- ...
731
+ ...
591
732
 
592
- const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
593
- await chatSDK.initialize();
733
+ const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
734
+ await chatSDK.initialize();
594
735
 
595
- let VoiceVideoCallingSDK;
596
- try {
597
- VoiceVideoCallingSDK = await chatSDK.getVoiceVideoCalling();
598
- console.log("VoiceVideoCalling loaded");
599
- } catch (e) {
600
- console.log(`Failed to load VoiceVideoCalling: ${e}`);
736
+ let VoiceVideoCallingSDK;
737
+ try {
738
+ VoiceVideoCallingSDK = await chatSDK.getVoiceVideoCalling();
739
+ console.log("VoiceVideoCalling loaded");
740
+ } catch (e) {
741
+ console.log(`Failed to load VoiceVideoCalling: ${e}`);
601
742
 
602
- if (e.message === 'UnsupportedPlatform') {
603
- // Voice Video Calling feature is not supported on this platform
604
- }
743
+ if (e.message === 'UnsupportedPlatform') {
744
+ // Voice Video Calling feature is not supported on this platform
745
+ }
605
746
 
606
- if (e.message === 'FeatureDisabled') {
607
- // Voice Video Calling feature is disabled on admin side
608
- }
747
+ if (e.message === 'FeatureDisabled') {
748
+ // Voice Video Calling feature is disabled on admin side
609
749
  }
750
+ }
610
751
 
611
- await chatSDK.startChat();
752
+ await chatSDK.startChat();
612
753
 
613
- const chatToken: any = await chatSDK.getChatToken();
614
-
615
- // Initialize only if VoiceVideoCallingSDK is defined
616
- if (VoiceVideoCallingSDK) {
617
- try {
618
- await VoiceVideoCallingSDK.initialize({
619
- chatToken,
620
- selfVideoHTMLElementId: 'selfVideo', // HTML element id where video stream of the agent will be rendered
621
- remoteVideoHTMLElementId: 'remoteVideo', // HTML element id where video stream of the customer will be rendered
622
- OCClient: chatSDK.OCClient
623
- });
624
- } catch (e) {
625
- console.error("Failed to initialize VoiceVideoCalling!");
626
- }
754
+ const chatToken: any = await chatSDK.getChatToken();
627
755
 
628
- // Triggered when there's an incoming call
629
- VoiceVideoCallingSDK.onCallAdded(() => {
630
- ...
756
+ // Initialize only if VoiceVideoCallingSDK is defined
757
+ if (VoiceVideoCallingSDK) {
758
+ try {
759
+ await VoiceVideoCallingSDK.initialize({
760
+ chatToken,
761
+ selfVideoHTMLElementId: 'selfVideo', // HTML element id where video stream of the agent will be rendered
762
+ remoteVideoHTMLElementId: 'remoteVideo', // HTML element id where video stream of the customer will be rendered
763
+ OCClient: chatSDK.OCClient
631
764
  });
765
+ } catch (e) {
766
+ console.error("Failed to initialize VoiceVideoCalling!");
767
+ }
632
768
 
633
- // Triggered when local video stream is available (e.g.: Local video added succesfully in selfVideoHTMLElement)
634
- VoiceVideoCallingSDK.onLocalVideoStreamAdded(() => {
635
- ...
636
- });
769
+ // Triggered when there's an incoming call
770
+ VoiceVideoCallingSDK.onCallAdded(() => {
771
+ ...
772
+ });
637
773
 
638
- // Triggered when local video stream is unavailable (e.g.: Customer turning off local video)
639
- VoiceVideoCallingSDK.onLocalVideoStreamRemoved(() => {
640
- ...
641
- });
774
+ // Triggered when local video stream is available (e.g.: Local video added succesfully in selfVideoHTMLElement)
775
+ VoiceVideoCallingSDK.onLocalVideoStreamAdded(() => {
776
+ ...
777
+ });
642
778
 
643
- // Triggered when remote video stream is available (e.g.: Remote video added succesfully in remoteVideoHTMLElement)
644
- VoiceVideoCallingSDK.onRemoteVideoStreamAdded(() => {
645
- ...
646
- });
779
+ // Triggered when local video stream is unavailable (e.g.: Customer turning off local video)
780
+ VoiceVideoCallingSDK.onLocalVideoStreamRemoved(() => {
781
+ ...
782
+ });
647
783
 
648
- // Triggered when remote video stream is unavailable (e.g.: Agent turning off remote video)
649
- VoiceVideoCallingSDK.onRemoteVideoStreamRemoved(() => {
650
- ...
651
- });
784
+ // Triggered when remote video stream is available (e.g.: Remote video added succesfully in remoteVideoHTMLElement)
785
+ VoiceVideoCallingSDK.onRemoteVideoStreamAdded(() => {
786
+ ...
787
+ });
652
788
 
653
- // Triggered when current call has ended or disconnected regardless the party
654
- VoiceVideoCalling.onCallDisconnected(() => {
655
- ...
656
- });
789
+ // Triggered when remote video stream is unavailable (e.g.: Agent turning off remote video)
790
+ VoiceVideoCallingSDK.onRemoteVideoStreamRemoved(() => {
791
+ ...
792
+ });
793
+
794
+ // Triggered when current call has ended or disconnected regardless the party
795
+ VoiceVideoCalling.onCallDisconnected(() => {
796
+ ...
797
+ });
657
798
 
658
- // Check if microphone is muted
659
- const isMicrophoneMuted = VoiceVideoCallingSDK.isMicrophoneMuted();
799
+ // Check if microphone is muted
800
+ const isMicrophoneMuted = VoiceVideoCallingSDK.isMicrophoneMuted();
660
801
 
661
- // Check if remote video is available
662
- const isRemoteVideoEnabled = VoiceVideoCallingSDK.isRemoteVideoEnabled();
802
+ // Check if remote video is available
803
+ const isRemoteVideoEnabled = VoiceVideoCallingSDK.isRemoteVideoEnabled();
663
804
 
664
- // Check if local video is available
665
- const isLocalVideoEnabled = VoiceVideoCallingSDK.isLocalVideoEnabled();
805
+ // Check if local video is available
806
+ const isLocalVideoEnabled = VoiceVideoCallingSDK.isLocalVideoEnabled();
666
807
 
667
- // Accepts incoming call
668
- const acceptCallConfig = {
669
- withVideo: true // Accept call with/without video stream
670
- };
671
- await VoiceVideoCallingSDK.acceptCall(acceptCallConfig);
808
+ // Accepts incoming call
809
+ const acceptCallConfig = {
810
+ withVideo: true // Accept call with/without video stream
811
+ };
812
+ await VoiceVideoCallingSDK.acceptCall(acceptCallConfig);
672
813
 
673
- // Rejects incoming call
674
- await VoiceVideoCallingSDK.rejectCall();
814
+ // Rejects incoming call
815
+ await VoiceVideoCallingSDK.rejectCall();
675
816
 
676
- // Ends/Stops current call
677
- await VoiceVideoCallingSDK.stopCall();
817
+ // Ends/Stops current call
818
+ await VoiceVideoCallingSDK.stopCall();
678
819
 
679
- // Mute/Unmute current call
680
- await VoiceVideoCallingSDK.toggleMute()
820
+ // Mute/Unmute current call
821
+ await VoiceVideoCallingSDK.toggleMute()
681
822
 
682
- // Display/Hide local video of current call
683
- await VoiceVideoCallingSDK.toggleLocalVideo()
823
+ // Display/Hide local video of current call
824
+ await VoiceVideoCallingSDK.toggleLocalVideo()
684
825
 
685
- // Clean up VoiceVideoCallingSDK (e.g.: Usually called when customer ends chat session)
686
- VoiceVideoCallingSDK.close();
687
- }
826
+ // Clean up VoiceVideoCallingSDK (e.g.: Usually called when customer ends chat session)
827
+ VoiceVideoCallingSDK.close();
828
+ }
688
829
  ```
689
830
 
690
831
  ## Feature Comparisons
@@ -729,20 +870,20 @@ Some of the data being collected are the following:
729
870
  If your organization is concerned about the data collected by the Chat SDK, you have the option to turn off automatic data collection by adding a flag in the `ChatSDKConfig`.
730
871
 
731
872
  ```ts
732
- const omnichannelConfig = {
733
- orgUrl: "",
734
- orgId: "",
735
- widgetId: ""
736
- };
873
+ const omnichannelConfig = {
874
+ orgUrl: "",
875
+ orgId: "",
876
+ widgetId: ""
877
+ };
737
878
 
738
- const chatSDKConfig = {
739
- telemetry: {
740
- disable: true // Disable telemetry
741
- }
742
- };
879
+ const chatSDKConfig = {
880
+ telemetry: {
881
+ disable: true // Disable telemetry
882
+ }
883
+ };
743
884
 
744
- const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
745
- await chatSDK.initialize();
885
+ const chatSDK = new OmnichannelChatSDK.OmnichannelChatSDK(omnichannelConfig, chatSDKConfig);
886
+ await chatSDK.initialize();
746
887
  ```
747
888
 
748
889
  # Contributing