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

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