@microsoft/omnichannel-chat-sdk 1.1.1-main.93f1eed → 1.1.1-main.a464993

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