@microsoft/omnichannel-chat-sdk 1.1.0 → 1.1.1-main.063303c

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